mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
replace ioutil with io package and other minor improvements
This commit is contained in:
parent
20d2855a66
commit
ef2643b046
|
@ -28,6 +28,7 @@ The codebase for Dependency Injection, Internationalization and localization and
|
|||
|
||||
## Fixes and Improvements
|
||||
|
||||
- Make the `Context.JSON` method customizable by modifying the `context.WriteJSON` package-level function.
|
||||
- Add new `iris.NewGuide` which helps you build a simple and nice JSON API with services as dependencies and better design pattern.
|
||||
- Make `Context.Domain()` customizable by letting developers to modify the `Context.GetDomain` package-level function.
|
||||
- Remove Request Context-based Transaction feature as its usage can be replaced with just the Iris Context (as of go1.7+) and better [project](_examples/project) structure.
|
||||
|
|
5
LICENSE
5
LICENSE
|
@ -1,4 +1,7 @@
|
|||
Copyright (c) 2017-2022 The Iris Authors. All rights reserved.
|
||||
Copyright (c) 2017-2022, The Iris Authors. All rights reserved.
|
||||
|
||||
The Iris Authors:
|
||||
* Gerasimos (Makis) Maropoulos
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
|
45
README.md
45
README.md
|
@ -19,7 +19,8 @@
|
|||
|
||||
Iris is a fast, simple yet fully featured and very efficient web framework for Go.
|
||||
|
||||
It provides a [beautifully](iris_guide.go#L31-L44) expressive and easy to use foundation for your next website or API.
|
||||
It provides a beautifully expressive and easy to use foundation for your next website or API.
|
||||
|
||||
|
||||
```go
|
||||
package main
|
||||
|
@ -27,18 +28,18 @@ package main
|
|||
import "github.com/kataras/iris/v12"
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.Use(iris.Compression)
|
||||
app := iris.New()
|
||||
app.Use(iris.Compression)
|
||||
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.HTML("Hello <strong>%s</strong>!", "World")
|
||||
})
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.HTML("Hello <strong>%s</strong>!", "World")
|
||||
})
|
||||
|
||||
app.Listen(":8080")
|
||||
app.Listen(":8080")
|
||||
}
|
||||
```
|
||||
|
||||
<details><summary>More with simple Handler</summary>
|
||||
<!-- <details><summary>More with simple Handler</summary>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
@ -178,6 +179,34 @@ func main() {
|
|||
|
||||
<br/>
|
||||
|
||||
-->
|
||||
|
||||
As one [Go developer](https://twitter.com/dkuye/status/1532087942696554497) once said, **Iris got you covered all-round and standing strong over the years**.
|
||||
|
||||
Some of the features Iris offers:
|
||||
|
||||
* HTTP/2 (Push, even Embedded data)
|
||||
* Middleware (Accesslog, Basicauth, CORS, gRPC, Anti-Bot hCaptcha, JWT, MethodOverride, ModRevision, Monitor, PPROF, Ratelimit, Anti-Bot reCaptcha, Recovery, RequestID, Rewrite)
|
||||
* API Versioning
|
||||
* Model-View-Controller
|
||||
* Websockets
|
||||
* gRPC
|
||||
* Auto-HTTPS
|
||||
* Builtin support for ngrok to put your app on the internet, the fastest way
|
||||
* Unique Router with dynamic path as parameter with standard types like :uuid, :string, :int... and the ability to create your own
|
||||
* Compression
|
||||
* View Engines (HTML, Django, Amber, Handlebars, Pug/Jade and more)
|
||||
* Create your own File Server and host your own WebDAV server
|
||||
* Cache
|
||||
* Localization (i18n, sitemap)
|
||||
* Sessions
|
||||
* Rich Responses (HTML, Text, Markdown, XML, YAML, Binary, JSON, JSONP, Protocol Buffers, MessagePack, Content Negotiation, Streaming, Server-Sent Events and more)
|
||||
* Response Compression (gzip, deflate, brotli, snappy, s2)
|
||||
* Rich Requests (Bind URL Query, Headers, Form, Text, XML, YAML, Binary, JSON, Validation, Protocol Buffers, MessagePack and more)
|
||||
* Dependency Injection (MVC, Handlers, API Routers)
|
||||
* Testing Suite
|
||||
* And the most important... you get fast answers and support from the 1st day until now - that's six full years!
|
||||
|
||||
Learn what [others saying about Iris](https://www.iris-go.com/#review) and **[star](https://github.com/kataras/iris/stargazers)** this open-source project to support its potentials.
|
||||
|
||||
[![](https://iris-go.com/images/reviews.gif)](https://iris-go.com/testimonials/)
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
@ -105,5 +104,5 @@ func BindResponse(resp *http.Response, dest interface{}) error {
|
|||
func RawResponse(resp *http.Response) ([]byte, error) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ioutil.ReadAll(resp.Body)
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
|
@ -51,7 +51,7 @@ func getExample() {
|
|||
}
|
||||
defer cr.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(cr)
|
||||
body, err := io.ReadAll(cr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ func postExample() {
|
|||
}
|
||||
defer cr.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(cr)
|
||||
body, err := io.ReadAll(cr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
@ -42,7 +42,7 @@ func getExample() {
|
|||
}
|
||||
defer r.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(r)
|
||||
body, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ func postExample() {
|
|||
}
|
||||
defer r.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(r)
|
||||
body, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ import (
|
|||
const addr = "127.0.0.1:8080"
|
||||
|
||||
/*
|
||||
$ go build -mod=mod -ldflags -H=windowsgui -o myapp.exe
|
||||
$ ./myapp.exe # run the app
|
||||
$ go build -mod=mod -ldflags -H=windowsgui -o myapp.exe
|
||||
$ ./myapp.exe # run the app
|
||||
*/
|
||||
func main() {
|
||||
go runServer()
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
const addr = "127.0.0.1:8080"
|
||||
|
||||
/*
|
||||
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
|
||||
$ ./myapp.exe # run
|
||||
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
|
||||
$ ./myapp.exe # run
|
||||
*/
|
||||
func main() {
|
||||
go runServer()
|
||||
|
|
|
@ -8,21 +8,21 @@ import (
|
|||
const addr = "127.0.0.1:8080"
|
||||
|
||||
/*
|
||||
# Windows requires special linker flags for GUI apps.
|
||||
# It's also recommended to use TDM-GCC-64 compiler for CGo.
|
||||
# http://tdm-gcc.tdragon.net/download
|
||||
#
|
||||
#
|
||||
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
|
||||
$ ./myapp.exe # run
|
||||
#
|
||||
# MacOS uses app bundles for GUI apps
|
||||
$ mkdir -p example.app/Contents/MacOS
|
||||
$ go build -o example.app/Contents/MacOS/example
|
||||
$ open example.app # Or click on the app in Finder
|
||||
#
|
||||
# Note: if you see "use option -std=c99 or -std=gnu99 to compile your code"
|
||||
# please refer to: https://github.com/webview/webview/issues/188
|
||||
# Windows requires special linker flags for GUI apps.
|
||||
# It's also recommended to use TDM-GCC-64 compiler for CGo.
|
||||
# http://tdm-gcc.tdragon.net/download
|
||||
#
|
||||
#
|
||||
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
|
||||
$ ./myapp.exe # run
|
||||
#
|
||||
# MacOS uses app bundles for GUI apps
|
||||
$ mkdir -p example.app/Contents/MacOS
|
||||
$ go build -o example.app/Contents/MacOS/example
|
||||
$ open example.app # Or click on the app in Finder
|
||||
#
|
||||
# Note: if you see "use option -std=c99 or -std=gnu99 to compile your code"
|
||||
# please refer to: https://github.com/webview/webview/issues/188
|
||||
*/
|
||||
func main() {
|
||||
go runServer()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -47,7 +47,7 @@ func (r resource) loadFromBase(dir string, strip string) string {
|
|||
|
||||
fullpath := filepath.Join(dir, filename)
|
||||
|
||||
b, err := ioutil.ReadFile(fullpath)
|
||||
b, err := os.ReadFile(fullpath)
|
||||
if err != nil {
|
||||
panic(fullpath + " failed with error: " + err.Error())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||
|
||||
//Package main generated by go-bindata.// sources:
|
||||
// Package main generated by go-bindata.// sources:
|
||||
// assets/css/main.css
|
||||
// assets/favicon.ico
|
||||
// assets/js/main.js
|
||||
|
@ -11,7 +11,6 @@ import (
|
|||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -288,11 +287,13 @@ var _bindata = map[string]func() (*asset, error){
|
|||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
|
@ -348,7 +349,7 @@ func RestoreAsset(dir, name string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -46,7 +46,7 @@ func (r resource) loadFromBase(dir string) string {
|
|||
|
||||
fullpath := filepath.Join(dir, filename)
|
||||
|
||||
b, err := ioutil.ReadFile(fullpath)
|
||||
b, err := os.ReadFile(fullpath)
|
||||
if err != nil {
|
||||
panic(fullpath + " failed with error: " + err.Error())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||
|
||||
//Package main generated by go-bindata.// sources:
|
||||
// Package main generated by go-bindata.// sources:
|
||||
// ../embedding-files-into-app/assets/css/main.css
|
||||
// ../embedding-files-into-app/assets/favicon.ico
|
||||
// ../embedding-files-into-app/assets/js/main.js
|
||||
|
@ -11,7 +11,6 @@ import (
|
|||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -288,11 +287,13 @@ var _bindata = map[string]func() (*asset, error){
|
|||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
|
@ -348,7 +349,7 @@ func RestoreAsset(dir, name string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -48,7 +48,7 @@ func (r resource) loadFromBase(dir string) string {
|
|||
|
||||
fullpath := filepath.Join(dir, filename)
|
||||
|
||||
b, err := ioutil.ReadFile(fullpath)
|
||||
b, err := os.ReadFile(fullpath)
|
||||
if err != nil {
|
||||
panic(fullpath + " failed with error: " + err.Error())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||
|
||||
//Package main generated by go-bindata.// sources:
|
||||
// Package main generated by go-bindata.// sources:
|
||||
// ../http2push/assets/app2/app2app3/css/main.css
|
||||
// ../http2push/assets/app2/app2app3/dirs/dir1/text.txt
|
||||
// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt
|
||||
|
@ -19,7 +19,6 @@ import (
|
|||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -464,11 +463,13 @@ var _bindata = map[string]func() (*asset, error){
|
|||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
|
@ -546,7 +547,7 @@ func RestoreAsset(dir, name string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||
|
||||
//Package main generated by go-bindata.// sources:
|
||||
// Package main generated by go-bindata.// sources:
|
||||
// ../http2push/assets/app2/app2app3/css/main.css
|
||||
// ../http2push/assets/app2/app2app3/dirs/dir1/text.txt
|
||||
// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt
|
||||
|
@ -19,7 +19,6 @@ import (
|
|||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -464,11 +463,13 @@ var _bindata = map[string]func() (*asset, error){
|
|||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
|
@ -546,7 +547,7 @@ func RestoreAsset(dir, name string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||
|
||||
//Package main generated by go-bindata.// sources:
|
||||
// Package main generated by go-bindata.// sources:
|
||||
// public/app.js
|
||||
// public/css/main.css
|
||||
// public/index.html
|
||||
|
@ -11,7 +11,6 @@ import (
|
|||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -288,11 +287,13 @@ var _bindata = map[string]func() (*asset, error){
|
|||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
|
@ -346,7 +347,7 @@ func RestoreAsset(dir, name string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -310,11 +309,13 @@ var _bindata = map[string]func() (*asset, error){
|
|||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||
|
@ -377,7 +378,7 @@ func RestoreAsset(dir, name string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -41,7 +41,7 @@ func (r resource) loadFromBase(dir string) string {
|
|||
|
||||
fullpath := filepath.Join(dir, filename)
|
||||
|
||||
b, err := ioutil.ReadFile(fullpath)
|
||||
b, err := os.ReadFile(fullpath)
|
||||
if err != nil {
|
||||
panic(fullpath + " failed with error: " + err.Error())
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
|
@ -40,7 +40,7 @@ func (r resource) loadFromBase(dir string) string {
|
|||
|
||||
fullpath := filepath.Join(dir, filename)
|
||||
|
||||
b, err := ioutil.ReadFile(fullpath)
|
||||
b, err := os.ReadFile(fullpath)
|
||||
if err != nil {
|
||||
panic(fullpath + " failed with error: " + err.Error())
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
/*Package main is a proxy + accesslog example.
|
||||
/*
|
||||
Package main is a proxy + accesslog example.
|
||||
In this example we will make a small proxy which listens requests on "/proxy/+path".
|
||||
With two accesslog instances, one for the main application and one for the /proxy/ requests.
|
||||
Of cource, you could a single accesslog for the whole application, but for the sake of the example
|
||||
let's log them separately.
|
||||
|
||||
We will make use of iris.StripPrefix and host.ProxyHandler.*/
|
||||
We will make use of iris.StripPrefix and host.ProxyHandler.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
|
|
|
@ -5,15 +5,15 @@ import (
|
|||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
pb "github.com/kataras/iris/v12/_examples/mvc/grpc-compatible/helloworld"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b, err := ioutil.ReadFile("../server.crt")
|
||||
b, err := os.ReadFile("../server.crt")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -30,14 +30,16 @@ type UsersController struct {
|
|||
// curl -i -u admin:password http://localhost:8080/users
|
||||
//
|
||||
// The correct way if you have sensitive data:
|
||||
// func (c *UsersController) Get() (results []viewmodels.User) {
|
||||
// data := c.Service.GetAll()
|
||||
//
|
||||
// for _, user := range data {
|
||||
// results = append(results, viewmodels.User{user})
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
// func (c *UsersController) Get() (results []viewmodels.User) {
|
||||
// data := c.Service.GetAll()
|
||||
//
|
||||
// for _, user := range data {
|
||||
// results = append(results, viewmodels.User{user})
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// otherwise just return the datamodels.
|
||||
func (c *UsersController) Get() (results []datamodels.User) {
|
||||
return c.Service.GetAll()
|
||||
|
|
|
@ -9,9 +9,11 @@ else as well, otherwise I am going with the first one:
|
|||
|
||||
```go
|
||||
// 1
|
||||
mvc.Configure(app.Party("/user"), func(m *mvc.Application) {
|
||||
m.Router.Use(cache.Handler(10*time.Second))
|
||||
})
|
||||
|
||||
mvc.Configure(app.Party("/user"), func(m *mvc.Application) {
|
||||
m.Router.Use(cache.Handler(10*time.Second))
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
```go
|
||||
|
@ -32,10 +34,12 @@ mvc.Configure(userRouter, ...)
|
|||
```go
|
||||
// 4
|
||||
// same:
|
||||
app.PartyFunc("/user", func(r iris.Party){
|
||||
r.Use(cache.Handler(10*time.Second))
|
||||
mvc.Configure(r, ...)
|
||||
})
|
||||
|
||||
app.PartyFunc("/user", func(r iris.Party){
|
||||
r.Use(cache.Handler(10*time.Second))
|
||||
mvc.Configure(r, ...)
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
If you want to use a middleware for a single route,
|
||||
|
@ -48,16 +52,18 @@ then you just call it on the method:
|
|||
var myMiddleware := myMiddleware.New(...) // this should return an iris/context.Handler
|
||||
|
||||
type UserController struct{}
|
||||
func (c *UserController) GetSomething(ctx iris.Context) {
|
||||
// ctx.Proceed checks if myMiddleware called `ctx.Next()`
|
||||
// inside it and returns true if so, otherwise false.
|
||||
nextCalled := ctx.Proceed(myMiddleware)
|
||||
if !nextCalled {
|
||||
return
|
||||
}
|
||||
|
||||
// else do the job here, it's allowed
|
||||
}
|
||||
func (c *UserController) GetSomething(ctx iris.Context) {
|
||||
// ctx.Proceed checks if myMiddleware called `ctx.Next()`
|
||||
// inside it and returns true if so, otherwise false.
|
||||
nextCalled := ctx.Proceed(myMiddleware)
|
||||
if !nextCalled {
|
||||
return
|
||||
}
|
||||
|
||||
// else do the job here, it's allowed
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
And last, if you want to add a middleware on a specific method
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/*Package main shows how to add done handlers in an MVC application without
|
||||
/*
|
||||
Package main shows how to add done handlers in an MVC application without
|
||||
the necessity of `ctx.Next()` inside the controller's methods.
|
||||
|
||||
When we want the `Done` handlers of that specific mvc app's `Party`
|
||||
to be executed but we don't want to add `ctx.Next()` on the `exampleController#EndRequest`*/
|
||||
to be executed but we don't want to add `ctx.Next()` on the `exampleController#EndRequest`
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
|
|
|
@ -28,42 +28,45 @@ func pong(ctx iris.Context) {
|
|||
}
|
||||
|
||||
/*
|
||||
+-------------------+
|
||||
| Env (DEV, PROD) |
|
||||
+---------+---------+
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
DEV | | | PROD
|
||||
+-------------------+
|
||||
| Env (DEV, PROD) |
|
||||
+---------+---------+
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
DEV | | | PROD
|
||||
|
||||
-------------------+---------------------+ | +----------------------+-------------------
|
||||
| | |
|
||||
| | |
|
||||
+---+-----+ +----------------v------------------+ +----+----+
|
||||
| sqlite | | NewDB(Env) DB | | mysql |
|
||||
+---+-----+ +----------------+---+--------------+ +----+----+
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
+--------------+-----+ +-------------------v---v-----------------+ +----+------+
|
||||
| greeterWithLogging | | NewGreetService(Env, DB) GreetService | | greeter |
|
||||
+--------------+-----+ +---------------------------+-------------+ +----+------+
|
||||
| | |
|
||||
| | |
|
||||
| +-----------------------------------------+ |
|
||||
| | GreetController | | |
|
||||
| | | | |
|
||||
| | - Service GreetService <-- | |
|
||||
| | | |
|
||||
| +-------------------+---------------------+ |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| +-----------+-----------+ |
|
||||
| | HTTP Request | |
|
||||
| +-----------------------+ |
|
||||
| | /greet?name=kataras | |
|
||||
| +-----------+-----------+ |
|
||||
| | |
|
||||
|
||||
| | |
|
||||
| | |
|
||||
+---+-----+ +----------------v------------------+ +----+----+
|
||||
| sqlite | | NewDB(Env) DB | | mysql |
|
||||
+---+-----+ +----------------+---+--------------+ +----+----+
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
+--------------+-----+ +-------------------v---v-----------------+ +----+------+
|
||||
| greeterWithLogging | | NewGreetService(Env, DB) GreetService | | greeter |
|
||||
+--------------+-----+ +---------------------------+-------------+ +----+------+
|
||||
| | |
|
||||
| | |
|
||||
| +-----------------------------------------+ |
|
||||
| | GreetController | | |
|
||||
| | | | |
|
||||
| | - Service GreetService <-- | |
|
||||
| | | |
|
||||
| +-------------------+---------------------+ |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| +-----------+-----------+ |
|
||||
| | HTTP Request | |
|
||||
| +-----------------------+ |
|
||||
| | /greet?name=kataras | |
|
||||
| +-----------+-----------+ |
|
||||
| | |
|
||||
|
||||
+------------------+--------+ +------------+------------+ +-------+------------------+
|
||||
| model.Response (JSON) | | Response (JSON, error) | | Bad Request |
|
||||
+---------------------------+ +-------------------------+ +--------------------------+
|
||||
|
|
|
@ -23,14 +23,16 @@ type MovieController struct {
|
|||
// curl -i http://localhost:8080/movies
|
||||
//
|
||||
// The correct way if you have sensitive data:
|
||||
// func (c *MovieController) Get() (results []viewmodels.Movie) {
|
||||
// data := c.Service.GetAll()
|
||||
//
|
||||
// for _, movie := range data {
|
||||
// results = append(results, viewmodels.Movie{movie})
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
// func (c *MovieController) Get() (results []viewmodels.Movie) {
|
||||
// data := c.Service.GetAll()
|
||||
//
|
||||
// for _, movie := range data {
|
||||
// results = append(results, viewmodels.Movie{movie})
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// otherwise just return the datamodels.
|
||||
func (c *MovieController) Get() (results []datamodels.Movie) {
|
||||
return c.Service.GetAll()
|
||||
|
|
|
@ -18,7 +18,7 @@ func (srv *Server) buildRouter() {
|
|||
ServerName: srv.config.ServerName,
|
||||
Env: srv.config.Env,
|
||||
Developer: "kataras",
|
||||
TimeLocation: time.FixedZone("Greece/Athens", 10800),
|
||||
TimeLocation: time.FixedZone("Greece/Athens", 7200),
|
||||
}))
|
||||
|
||||
api := srv.Party("/api")
|
||||
|
|
|
@ -8,7 +8,7 @@ func main() {
|
|||
app := iris.New()
|
||||
|
||||
app.Post("/", logAllBody, logJSON, logFormValues, func(ctx iris.Context) {
|
||||
// body, err := ioutil.ReadAll(ctx.Request().Body) once or
|
||||
// body, err := io.ReadAll(ctx.Request().Body) once or
|
||||
body, err := ctx.GetBody() // as many times as you need.
|
||||
if err != nil {
|
||||
ctx.StopWithError(iris.StatusInternalServerError, err)
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
|
@ -69,7 +69,7 @@ func TestContentNegotiation(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rawResponse, err := ioutil.ReadAll(zr)
|
||||
rawResponse, err := io.ReadAll(zr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -7,14 +7,15 @@ import (
|
|||
"github.com/kataras/iris/v12/core/router"
|
||||
)
|
||||
|
||||
/* A Router should contain all three of the following methods:
|
||||
- HandleRequest should handle the request based on the Context.
|
||||
HandleRequest(ctx iris.Context)
|
||||
- Build should builds the handler, it's being called on router's BuildRouter.
|
||||
Build(provider router.RoutesProvider) error
|
||||
- RouteExists reports whether a particular route exists.
|
||||
RouteExists(ctx iris.Context, method, path string) bool
|
||||
- FireErrorCode(ctx iris.Context) should handle the given ctx.GetStatusCode().
|
||||
/*
|
||||
A Router should contain all three of the following methods:
|
||||
- HandleRequest should handle the request based on the Context.
|
||||
HandleRequest(ctx iris.Context)
|
||||
- Build should builds the handler, it's being called on router's BuildRouter.
|
||||
Build(provider router.RoutesProvider) error
|
||||
- RouteExists reports whether a particular route exists.
|
||||
RouteExists(ctx iris.Context, method, path string) bool
|
||||
- FireErrorCode(ctx iris.Context) should handle the given ctx.GetStatusCode().
|
||||
|
||||
For a more detailed, complete and useful example
|
||||
you can take a look at the iris' router itself which is located at:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -29,7 +29,7 @@ func (r resource) loadFromBase(dir string) string {
|
|||
|
||||
fullpath := filepath.Join(dir, filename)
|
||||
|
||||
b, err := ioutil.ReadFile(fullpath)
|
||||
b, err := os.ReadFile(fullpath)
|
||||
if err != nil {
|
||||
panic(fullpath + " failed with error: " + err.Error())
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/*Package main is a simple example of the behavior change of the execution flow of the handlers,
|
||||
/*
|
||||
Package main is a simple example of the behavior change of the execution flow of the handlers,
|
||||
normally we need the `ctx.Next()` to call the next handler in a route's handler chain,
|
||||
but with the `ExecutionRules` we can change this default behavior.
|
||||
Please read below before continue.
|
||||
|
@ -8,11 +9,11 @@ The `Party#SetExecutionRules` alters the execution flow of the route handlers.
|
|||
For example, if for some reason the desired result is the (done or all) handlers
|
||||
to be executed no matter what, even if no `ctx.Next()` is called in the previous handlers:
|
||||
|
||||
app.SetExecutionRules(iris.ExecutionRules {
|
||||
Begin: iris.ExecutionOptions{Force: true}, # begin handlers(.Use)
|
||||
Main: iris.ExecutionOptions{Force: true}, # main handler (.Handle/Get...)
|
||||
Done: iris.ExecutionOptions{Force: true}, # done handlers (.Done)
|
||||
})
|
||||
app.SetExecutionRules(iris.ExecutionRules {
|
||||
Begin: iris.ExecutionOptions{Force: true}, # begin handlers(.Use)
|
||||
Main: iris.ExecutionOptions{Force: true}, # main handler (.Handle/Get...)
|
||||
Done: iris.ExecutionOptions{Force: true}, # done handlers (.Done)
|
||||
})
|
||||
|
||||
Note that if `true` then the only remained way to "break" the handler chain
|
||||
is by calling the `ctx.StopExecution()` (now that `ctx.Next()` doesn't even matter).
|
||||
|
@ -22,7 +23,6 @@ the same rules will be applied to that as well.
|
|||
|
||||
Reset of these rules to their defaults (before `Party#Handle`) can be done
|
||||
with `Party#SetExecutionRules(iris.ExecutionRules{})`.
|
||||
|
||||
*/
|
||||
package main
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -14,7 +13,7 @@ import (
|
|||
// The rest possible checks is up to you, take it as as an exercise!
|
||||
func TestURLShortener(t *testing.T) {
|
||||
// temp db file
|
||||
f, err := ioutil.TempFile("", "shortener")
|
||||
f, err := os.CreateTemp("", "shortener")
|
||||
if err != nil {
|
||||
t.Fatalf("creating temp file for database failed: %v", err)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||
|
||||
//Package main generated by go-bindata.// sources:
|
||||
// Package main generated by go-bindata.// sources:
|
||||
// templates/layouts/layout.html
|
||||
// templates/layouts/mylayout.html
|
||||
// templates/page1.html
|
||||
|
@ -12,7 +12,6 @@ import (
|
|||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -310,11 +309,13 @@ var _bindata = map[string]func() (*asset, error){
|
|||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
|
@ -371,7 +372,7 @@ func RestoreAsset(dir, name string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -266,11 +265,13 @@ var _bindata = map[string]func() (*asset, error){
|
|||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||
|
@ -323,7 +324,7 @@ func RestoreAsset(dir, name string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -332,11 +331,13 @@ var _bindata = map[string]func() (*asset, error){
|
|||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||
|
@ -394,7 +395,7 @@ func RestoreAsset(dir, name string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -310,11 +309,13 @@ var _bindata = map[string]func() (*asset, error){
|
|||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||
|
@ -371,7 +372,7 @@ func RestoreAsset(dir, name string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -266,11 +265,13 @@ var _bindata = map[string]func() (*asset, error){
|
|||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||
|
@ -321,7 +322,7 @@ func RestoreAsset(dir, name string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ package main
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
@ -53,7 +52,7 @@ func readFileIfModified(lastMod time.Time) ([]byte, time.Time, error) {
|
|||
if !fi.ModTime().After(lastMod) {
|
||||
return nil, lastMod, nil
|
||||
}
|
||||
p, err := ioutil.ReadFile(filename)
|
||||
p, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, fi.ModTime(), err
|
||||
}
|
||||
|
|
|
@ -13,12 +13,13 @@ import (
|
|||
// The cases are filtered in order of their registration.
|
||||
//
|
||||
// Example Code:
|
||||
// switcher := Switch(Hosts{
|
||||
// "mydomain.com": app,
|
||||
// "test.mydomain.com": testSubdomainApp,
|
||||
// "otherdomain.com": "appName",
|
||||
// })
|
||||
// switcher.Listen(":80")
|
||||
//
|
||||
// switcher := Switch(Hosts{
|
||||
// "mydomain.com": app,
|
||||
// "test.mydomain.com": testSubdomainApp,
|
||||
// "otherdomain.com": "appName",
|
||||
// })
|
||||
// switcher.Listen(":80")
|
||||
//
|
||||
// Note that this is NOT an alternative for a load balancer.
|
||||
// The filters are executed by registration order and a matched Application
|
||||
|
|
14
auth/auth.go
14
auth/auth.go
|
@ -99,6 +99,7 @@ func MustLoad[T User](filename string) *Auth[T] {
|
|||
// Must is a helper that wraps a call to a function returning (*Auth[T], error)
|
||||
// and panics if the error is non-nil. It is intended for use in variable
|
||||
// initializations such as
|
||||
//
|
||||
// var s = auth.Must(auth.New[MyUser](config))
|
||||
func Must[T User](s *Auth[T], err error) *Auth[T] {
|
||||
if err != nil {
|
||||
|
@ -142,12 +143,13 @@ func New[T User](config Configuration) (*Auth[T], error) {
|
|||
// method when a Provider of T and ErrorHandler is available through the registered Party's dependencies.
|
||||
//
|
||||
// Usage Example:
|
||||
// api := app.Party("/api")
|
||||
// api.EnsureStaticBindings().RegisterDependency(
|
||||
// NewAuthProviderErrorHandler(),
|
||||
// NewAuthCustomerProvider,
|
||||
// auth.Must(auth.New[Customer](authConfig)).WithProviderAndErrorHandler,
|
||||
// )
|
||||
//
|
||||
// api := app.Party("/api")
|
||||
// api.EnsureStaticBindings().RegisterDependency(
|
||||
// NewAuthProviderErrorHandler(),
|
||||
// NewAuthCustomerProvider,
|
||||
// auth.Must(auth.New[Customer](authConfig)).WithProviderAndErrorHandler,
|
||||
// )
|
||||
func (s *Auth[T]) WithProviderAndErrorHandler(provider Provider[T], errHandler ErrorHandler) *Auth[T] {
|
||||
if provider != nil {
|
||||
for i := range s.providers {
|
||||
|
|
9
cache/browser.go
vendored
9
cache/browser.go
vendored
|
@ -49,10 +49,11 @@ var NoCache = func(ctx *context.Context) {
|
|||
// Usage: `app.Use(cache.StaticCache(24 * time.Hour))` or `app.Use(cache.Staticcache(-1))`.
|
||||
// A middleware, which is a simple Handler can be called inside another handler as well, example:
|
||||
// cacheMiddleware := cache.StaticCache(...)
|
||||
// func(ctx iris.Context){
|
||||
// cacheMiddleware(ctx)
|
||||
// [...]
|
||||
// }
|
||||
//
|
||||
// func(ctx iris.Context){
|
||||
// cacheMiddleware(ctx)
|
||||
// [...]
|
||||
// }
|
||||
var StaticCache = func(cacheDur time.Duration) context.Handler {
|
||||
if int64(cacheDur) <= 0 {
|
||||
return NoCache
|
||||
|
|
6
cache/client/client.go
vendored
6
cache/client/client.go
vendored
|
@ -2,7 +2,7 @@ package client
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
|
@ -17,8 +17,8 @@ import (
|
|||
// register one client handler per route.
|
||||
//
|
||||
// it's just calls a remote cache service server/handler,
|
||||
// which lives on other, external machine.
|
||||
//
|
||||
// which lives on other, external machine.
|
||||
type ClientHandler struct {
|
||||
// bodyHandler the original route's handler
|
||||
bodyHandler context.Handler
|
||||
|
@ -162,7 +162,7 @@ func (h *ClientHandler) ServeHTTP(ctx *context.Context) {
|
|||
// get the status code , content type and the write the response body
|
||||
ctx.ContentType(response.Header.Get(cfg.ContentTypeHeader))
|
||||
ctx.StatusCode(response.StatusCode)
|
||||
responseBody, err := ioutil.ReadAll(response.Body)
|
||||
responseBody, err := io.ReadAll(response.Body)
|
||||
response.Body.Close()
|
||||
if err != nil {
|
||||
return
|
||||
|
|
13
cache/client/rule/validator.go
vendored
13
cache/client/rule/validator.go
vendored
|
@ -22,12 +22,13 @@ type PreValidator func(*context.Context) bool
|
|||
//
|
||||
// Q: What's the difference between this and a PreValidator?
|
||||
// A: PreValidator runs BEFORE trying to get the cache, it cares only for the request
|
||||
// and if at least one PreValidator returns false then it just runs the original handler and stop there, at the other hand
|
||||
// a PostValidator runs if all PreValidators returns true and original handler is executed but with a response recorder,
|
||||
// also the PostValidator should return true to store the cached response.
|
||||
// Last, a PostValidator accepts a context
|
||||
// in order to be able to catch the original handler's response,
|
||||
// the PreValidator checks only for request.
|
||||
//
|
||||
// and if at least one PreValidator returns false then it just runs the original handler and stop there, at the other hand
|
||||
// a PostValidator runs if all PreValidators returns true and original handler is executed but with a response recorder,
|
||||
// also the PostValidator should return true to store the cached response.
|
||||
// Last, a PostValidator accepts a context
|
||||
// in order to be able to catch the original handler's response,
|
||||
// the PreValidator checks only for request.
|
||||
//
|
||||
// If a function of type of PostValidator returns true then the (shared-always) cache is allowed to be stored.
|
||||
type PostValidator func(*context.Context) bool
|
||||
|
|
|
@ -2,7 +2,6 @@ package iris
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
|
@ -65,7 +64,7 @@ func parseYAML(filename string) (Configuration, error) {
|
|||
}
|
||||
|
||||
// read the raw contents of the file
|
||||
data, err := ioutil.ReadFile(yamlAbsPath)
|
||||
data, err := os.ReadFile(yamlAbsPath)
|
||||
if err != nil {
|
||||
return c, fmt.Errorf("parse yaml: %w", err)
|
||||
}
|
||||
|
@ -112,7 +111,6 @@ func YAML(filename string) Configuration {
|
|||
// Read more about toml's implementation at:
|
||||
// https://github.com/toml-lang/toml
|
||||
//
|
||||
//
|
||||
// Accepts the absolute path of the configuration file.
|
||||
// An error will be shown to the user via panic with the error message.
|
||||
// Error may occur when the file does not exist or is not formatted correctly.
|
||||
|
@ -144,7 +142,7 @@ func TOML(filename string) Configuration {
|
|||
}
|
||||
|
||||
// read the raw contents of the file
|
||||
data, err := ioutil.ReadFile(tomlAbsPath)
|
||||
data, err := os.ReadFile(tomlAbsPath)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("toml :%w", err))
|
||||
}
|
||||
|
@ -754,6 +752,7 @@ type Configuration struct {
|
|||
// then the application tries to optimize for the best performance where is possible.
|
||||
//
|
||||
// Defaults to false.
|
||||
// Deprecated. As of version 12.2.x this field does nothing.
|
||||
EnableOptimizations bool `ini:"enable_optimizations" json:"enableOptimizations,omitempty" yaml:"EnableOptimizations" toml:"EnableOptimizations"`
|
||||
// EnableProtoJSON when this field is true
|
||||
// enables the proto marshaler on given proto messages when calling the Context.JSON method.
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package iris
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
@ -103,7 +102,7 @@ func createGlobalConfiguration(t *testing.T) {
|
|||
out, err := yaml.Marshal(&c)
|
||||
|
||||
if err == nil {
|
||||
err = ioutil.WriteFile(filename, out, os.FileMode(0666))
|
||||
err = os.WriteFile(filename, out, os.FileMode(0666))
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("error while writing the global configuration field at: %s. Trace: %v\n", filename, err)
|
||||
|
@ -131,7 +130,7 @@ func testConfigurationGlobal(t *testing.T, c Configurator) {
|
|||
}
|
||||
|
||||
func TestConfigurationYAML(t *testing.T) {
|
||||
yamlFile, ferr := ioutil.TempFile("", "configuration.yml")
|
||||
yamlFile, ferr := os.CreateTemp("", "configuration.yml")
|
||||
|
||||
if ferr != nil {
|
||||
t.Fatal(ferr)
|
||||
|
@ -264,7 +263,7 @@ Other:
|
|||
}
|
||||
|
||||
func TestConfigurationTOML(t *testing.T) {
|
||||
tomlFile, ferr := ioutil.TempFile("", "configuration.toml")
|
||||
tomlFile, ferr := os.CreateTemp("", "configuration.toml")
|
||||
|
||||
if ferr != nil {
|
||||
t.Fatal(ferr)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -166,10 +166,12 @@ func (u *SimpleUser) GetField(key string) (interface{}, error) {
|
|||
|
||||
// UserMap can be used to convert a common map[string]interface{} to a User.
|
||||
// Usage:
|
||||
// user := map[string]interface{}{
|
||||
// "username": "kataras",
|
||||
// "age" : 27,
|
||||
// }
|
||||
//
|
||||
// user := map[string]interface{}{
|
||||
// "username": "kataras",
|
||||
// "age" : 27,
|
||||
// }
|
||||
//
|
||||
// ctx.SetUser(user)
|
||||
// OR
|
||||
// user := UserStruct{....}
|
||||
|
|
|
@ -275,7 +275,6 @@ type Filter func(*Context) bool
|
|||
// Handlers here should act like middleware, they should contain `ctx.Next` to proceed
|
||||
// to the next handler of the chain. Those "handlers" are registered to the per-request context.
|
||||
//
|
||||
//
|
||||
// It checks the "filter" and if passed then
|
||||
// it, correctly, executes the "handlers".
|
||||
//
|
||||
|
|
|
@ -131,11 +131,12 @@ func (r *RequestParams) GetIntUnslashed(key string) (int, bool) {
|
|||
// Key is the specific type, which should be unique.
|
||||
// The value is a function which accepts the parameter index
|
||||
// and it should return the value as the parameter type evaluator expects it.
|
||||
// i.e [reflect.TypeOf("string")] = func(paramIndex int) interface{} {
|
||||
// return func(ctx *Context) <T> {
|
||||
// return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(<T>)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// i.e [reflect.TypeOf("string")] = func(paramIndex int) interface{} {
|
||||
// return func(ctx *Context) <T> {
|
||||
// return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(<T>)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Read https://github.com/kataras/iris/tree/master/_examples/routing/macros for more details.
|
||||
// Checks for total available request parameters length
|
||||
|
@ -261,7 +262,9 @@ var ParamResolvers = map[reflect.Type]func(paramIndex int) interface{}{
|
|||
// and the parameter's index based on the registered path.
|
||||
// Usage: nameResolver := ParamResolverByKindAndKey(reflect.TypeOf(""), 0)
|
||||
// Inside a Handler: nameResolver.Call(ctx)[0]
|
||||
// it will return the reflect.Value Of the exact type of the parameter(based on the path parameters and macros).
|
||||
//
|
||||
// it will return the reflect.Value Of the exact type of the parameter(based on the path parameters and macros).
|
||||
//
|
||||
// It is only useful for dynamic binding of the parameter, it is used on "hero" package and it should be modified
|
||||
// only when Macros are modified in such way that the default selections for the available go std types are not enough.
|
||||
//
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"strconv"
|
||||
|
@ -32,7 +32,7 @@ func releaseResponseRecorder(w *ResponseRecorder) {
|
|||
// A ResponseRecorder is used mostly for testing
|
||||
// in order to record and modify, if necessary, the body and status code and headers.
|
||||
//
|
||||
// See `context.Recorder`` method too.
|
||||
// See `context.Recorder“ method too.
|
||||
type ResponseRecorder struct {
|
||||
ResponseWriter
|
||||
|
||||
|
@ -366,7 +366,7 @@ func (w *ResponseRecorder) Result() *http.Response { // a modified copy of net/h
|
|||
}
|
||||
res.Status = fmt.Sprintf("%03d %s", res.StatusCode, http.StatusText(res.StatusCode))
|
||||
if w.chunks != nil {
|
||||
res.Body = ioutil.NopCloser(bytes.NewReader(w.chunks))
|
||||
res.Body = io.NopCloser(bytes.NewReader(w.chunks))
|
||||
} else {
|
||||
res.Body = http.NoBody
|
||||
}
|
||||
|
|
|
@ -111,7 +111,6 @@ func StatusText(code int) string {
|
|||
// Read more at `iris/Configuration#DisableAutoFireStatusCode` and
|
||||
// `iris/core/router/Party#OnAnyErrorCode` for relative information.
|
||||
//
|
||||
//
|
||||
// Modify this variable when your Iris server or/and client
|
||||
// not follows the RFC: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||
var StatusCodeNotSuccessful = func(statusCode int) bool { return statusCode >= 400 }
|
||||
|
|
|
@ -10,9 +10,10 @@ import (
|
|||
// FromStd converts native http.Handler & http.HandlerFunc to context.Handler.
|
||||
//
|
||||
// Supported form types:
|
||||
// .FromStd(h http.Handler)
|
||||
// .FromStd(func(w http.ResponseWriter, r *http.Request))
|
||||
// .FromStd(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc))
|
||||
//
|
||||
// .FromStd(h http.Handler)
|
||||
// .FromStd(func(w http.ResponseWriter, r *http.Request))
|
||||
// .FromStd(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc))
|
||||
func FromStd(handler interface{}) context.Handler {
|
||||
switch h := handler.(type) {
|
||||
case context.Handler:
|
||||
|
|
|
@ -730,7 +730,6 @@ func (e Entry) Value() interface{} {
|
|||
// Save same as `Set`
|
||||
// However, if "immutable" is true then saves it as immutable (same as `SetImmutable`).
|
||||
//
|
||||
//
|
||||
// Returns the entry and true if it was just inserted, meaning that
|
||||
// it will return the entry and a false boolean if the entry exists and it has been updated.
|
||||
func (r *Store) Save(key string, value interface{}, immutable bool) (Entry, bool) {
|
||||
|
|
|
@ -377,8 +377,9 @@ func (api *APIBuilder) RegisterDependency(dependencies ...interface{}) {
|
|||
// (see ConfigureContainer().RegisterDependency)
|
||||
// or leave the framework to parse the request and fill the values accordingly.
|
||||
// The output of the "handlersFn" can be any output result:
|
||||
// custom structs <T>, string, []byte, int, error,
|
||||
// a combination of the above, hero.Result(hero.View | hero.Response) and more.
|
||||
//
|
||||
// custom structs <T>, string, []byte, int, error,
|
||||
// a combination of the above, hero.Result(hero.View | hero.Response) and more.
|
||||
//
|
||||
// If more than one handler function is registered
|
||||
// then the execution happens without the nessecity of the `Context.Next` method,
|
||||
|
@ -390,22 +391,22 @@ func (api *APIBuilder) RegisterDependency(dependencies ...interface{}) {
|
|||
// The client's request body and server's response body Go types.
|
||||
// Could be any data structure.
|
||||
//
|
||||
// type (
|
||||
// request struct {
|
||||
// Firstname string `json:"firstname"`
|
||||
// Lastname string `json:"lastname"`
|
||||
// }
|
||||
// type (
|
||||
// request struct {
|
||||
// Firstname string `json:"firstname"`
|
||||
// Lastname string `json:"lastname"`
|
||||
// }
|
||||
//
|
||||
// response struct {
|
||||
// ID uint64 `json:"id"`
|
||||
// Message string `json:"message"`
|
||||
// }
|
||||
// )
|
||||
// response struct {
|
||||
// ID uint64 `json:"id"`
|
||||
// Message string `json:"message"`
|
||||
// }
|
||||
// )
|
||||
//
|
||||
// Register the route hander.
|
||||
//
|
||||
// HTTP VERB ROUTE PATH ROUTE HANDLER
|
||||
// app.HandleFunc("PUT", "/users/{id:uint64}", updateUser)
|
||||
// HTTP VERB ROUTE PATH ROUTE HANDLER
|
||||
// app.HandleFunc("PUT", "/users/{id:uint64}", updateUser)
|
||||
//
|
||||
// Code the route handler function.
|
||||
// Path parameters and request body are binded
|
||||
|
@ -413,26 +414,26 @@ func (api *APIBuilder) RegisterDependency(dependencies ...interface{}) {
|
|||
// The "id" uint64 binds to "{id:uint64}" route path parameter and
|
||||
// the "input" binds to client request data such as JSON.
|
||||
//
|
||||
// func updateUser(id uint64, input request) response {
|
||||
// // [custom logic...]
|
||||
// func updateUser(id uint64, input request) response {
|
||||
// // [custom logic...]
|
||||
//
|
||||
// return response{
|
||||
// ID:id,
|
||||
// Message: "User updated successfully",
|
||||
// }
|
||||
// }
|
||||
// return response{
|
||||
// ID:id,
|
||||
// Message: "User updated successfully",
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Simulate a client request which sends data
|
||||
// to the server and prints out the response.
|
||||
//
|
||||
// curl --request PUT -d '{"firstname":"John","lastname":"Doe"}' \
|
||||
// -H "Content-Type: application/json" \
|
||||
// http://localhost:8080/users/42
|
||||
// curl --request PUT -d '{"firstname":"John","lastname":"Doe"}' \
|
||||
// -H "Content-Type: application/json" \
|
||||
// http://localhost:8080/users/42
|
||||
//
|
||||
// {
|
||||
// "id": 42,
|
||||
// "message": "User updated successfully"
|
||||
// }
|
||||
// {
|
||||
// "id": 42,
|
||||
// "message": "User updated successfully"
|
||||
// }
|
||||
//
|
||||
// See the `ConfigureContainer` for more features regrading
|
||||
// the dependency injection, mvc and function handlers.
|
||||
|
@ -474,11 +475,12 @@ func (api *APIBuilder) AllowMethods(methods ...string) Party {
|
|||
// For example, if for some reason the desired result is the (done or all) handlers to be executed no matter what
|
||||
// even if no `ctx.Next()` is called in the previous handlers, including the begin(`Use`),
|
||||
// the main(`Handle`) and the done(`Done`) handlers themselves, then:
|
||||
// Party#SetExecutionRules(iris.ExecutionRules {
|
||||
// Begin: iris.ExecutionOptions{Force: true},
|
||||
// Main: iris.ExecutionOptions{Force: true},
|
||||
// Done: iris.ExecutionOptions{Force: true},
|
||||
// })
|
||||
//
|
||||
// Party#SetExecutionRules(iris.ExecutionRules {
|
||||
// Begin: iris.ExecutionOptions{Force: true},
|
||||
// Main: iris.ExecutionOptions{Force: true},
|
||||
// Done: iris.ExecutionOptions{Force: true},
|
||||
// })
|
||||
//
|
||||
// Note that if : true then the only remained way to "break" the handler chain is by `ctx.StopExecution()` now that `ctx.Next()` does not matter.
|
||||
//
|
||||
|
@ -567,11 +569,14 @@ func (api *APIBuilder) handle(errorCode int, method string, relativePath string,
|
|||
// otherwise use `Party` which can handle many paths with different handlers and middlewares.
|
||||
//
|
||||
// Usage:
|
||||
// app.HandleMany("GET", "/user /user/{id:uint64} /user/me", genericUserHandler)
|
||||
//
|
||||
// app.HandleMany("GET", "/user /user/{id:uint64} /user/me", genericUserHandler)
|
||||
//
|
||||
// At the other side, with `Handle` we've had to write:
|
||||
// app.Handle("GET", "/user", userHandler)
|
||||
// app.Handle("GET", "/user/{id:uint64}", userByIDHandler)
|
||||
// app.Handle("GET", "/user/me", userMeHandler)
|
||||
//
|
||||
// app.Handle("GET", "/user", userHandler)
|
||||
// app.Handle("GET", "/user/{id:uint64}", userByIDHandler)
|
||||
// app.Handle("GET", "/user/me", userMeHandler)
|
||||
//
|
||||
// app.HandleMany("GET POST", "/path", handler)
|
||||
func (api *APIBuilder) HandleMany(methodOrMulti string, relativePathorMulti string, handlers ...context.Handler) (routes []*Route) {
|
||||
|
@ -606,7 +611,7 @@ func (api *APIBuilder) HandleMany(methodOrMulti string, relativePathorMulti stri
|
|||
//
|
||||
// Alternatively, to get just the handler for that look the FileServer function instead.
|
||||
//
|
||||
// api.HandleDir("/static", iris.Dir("./assets"), iris.DirOptions{IndexName: "/index.html", Compress: true})
|
||||
// api.HandleDir("/static", iris.Dir("./assets"), iris.DirOptions{IndexName: "/index.html", Compress: true})
|
||||
//
|
||||
// Returns all the registered routes, including GET index and path patterm and HEAD.
|
||||
//
|
||||
|
@ -904,12 +909,13 @@ func (api *APIBuilder) Party(relativePath string, handlers ...context.Handler) P
|
|||
// Note: `iris#Party` and `core/router#Party` describes the exactly same interface.
|
||||
//
|
||||
// Usage:
|
||||
// app.PartyFunc("/users", func(u iris.Party){
|
||||
// u.Use(authMiddleware, logMiddleware)
|
||||
// u.Get("/", getAllUsers)
|
||||
// u.Post("/", createOrUpdateUser)
|
||||
// u.Delete("/", deleteUser)
|
||||
// })
|
||||
//
|
||||
// app.PartyFunc("/users", func(u iris.Party){
|
||||
// u.Use(authMiddleware, logMiddleware)
|
||||
// u.Get("/", getAllUsers)
|
||||
// u.Post("/", createOrUpdateUser)
|
||||
// u.Delete("/", deleteUser)
|
||||
// })
|
||||
//
|
||||
// Look `Party` for more.
|
||||
func (api *APIBuilder) PartyFunc(relativePath string, partyBuilderFunc func(p Party)) Party {
|
||||
|
@ -949,16 +955,21 @@ type (
|
|||
// Useful when the api's dependencies amount are too much to pass on a function.
|
||||
//
|
||||
// Usage:
|
||||
// app.PartyConfigure("/users", &api.UsersAPI{UserRepository: ..., ...})
|
||||
//
|
||||
// app.PartyConfigure("/users", &api.UsersAPI{UserRepository: ..., ...})
|
||||
//
|
||||
// Where UsersAPI looks like:
|
||||
// type UsersAPI struct { [...] }
|
||||
// func(api *UsersAPI) Configure(router iris.Party) {
|
||||
// router.Get("/{id:uuid}", api.getUser)
|
||||
// [...]
|
||||
// }
|
||||
//
|
||||
// type UsersAPI struct { [...] }
|
||||
// func(api *UsersAPI) Configure(router iris.Party) {
|
||||
// router.Get("/{id:uuid}", api.getUser)
|
||||
// [...]
|
||||
// }
|
||||
//
|
||||
// Usage with (static) dependencies:
|
||||
// app.RegisterDependency(userRepo, ...)
|
||||
// app.PartyConfigure("/users", new(api.UsersAPI))
|
||||
//
|
||||
// app.RegisterDependency(userRepo, ...)
|
||||
// app.PartyConfigure("/users", new(api.UsersAPI))
|
||||
func (api *APIBuilder) PartyConfigure(relativePath string, partyReg ...PartyConfigurator) Party {
|
||||
var child Party
|
||||
|
||||
|
@ -1626,15 +1637,16 @@ func (api *APIBuilder) RegisterView(viewEngine context.ViewEngine) {
|
|||
|
||||
// FallbackView registers one or more fallback views for a template or a template layout.
|
||||
// Usage:
|
||||
// FallbackView(iris.FallbackView("fallback.html"))
|
||||
// FallbackView(iris.FallbackViewLayout("layouts/fallback.html"))
|
||||
// OR
|
||||
// FallbackView(iris.FallbackViewFunc(ctx iris.Context, err iris.ErrViewNotExist) error {
|
||||
// err.Name is the previous template name.
|
||||
// err.IsLayout reports whether the failure came from the layout template.
|
||||
// err.Data is the template data provided to the previous View call.
|
||||
// [...custom logic e.g. ctx.View("fallback", err.Data)]
|
||||
// })
|
||||
//
|
||||
// FallbackView(iris.FallbackView("fallback.html"))
|
||||
// FallbackView(iris.FallbackViewLayout("layouts/fallback.html"))
|
||||
// OR
|
||||
// FallbackView(iris.FallbackViewFunc(ctx iris.Context, err iris.ErrViewNotExist) error {
|
||||
// err.Name is the previous template name.
|
||||
// err.IsLayout reports whether the failure came from the layout template.
|
||||
// err.Data is the template data provided to the previous View call.
|
||||
// [...custom logic e.g. ctx.View("fallback", err.Data)]
|
||||
// })
|
||||
func (api *APIBuilder) FallbackView(provider context.FallbackViewProvider) {
|
||||
handler := func(ctx *context.Context) {
|
||||
ctx.FallbackView(provider)
|
||||
|
@ -1653,9 +1665,10 @@ func (api *APIBuilder) FallbackView(provider context.FallbackViewProvider) {
|
|||
// app := iris.New()
|
||||
// app.RegisterView(iris.$VIEW_ENGINE("./views", ".$extension"))
|
||||
// my := app.Party("/my").Layout("layouts/mylayout.html")
|
||||
// my.Get("/", func(ctx iris.Context) {
|
||||
// ctx.View("page1.html")
|
||||
// })
|
||||
//
|
||||
// my.Get("/", func(ctx iris.Context) {
|
||||
// ctx.View("page1.html")
|
||||
// })
|
||||
//
|
||||
// Examples: https://github.com/kataras/iris/tree/master/_examples/view
|
||||
func (api *APIBuilder) Layout(tmplLayoutFile string) Party {
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"github.com/kataras/golog"
|
||||
)
|
||||
|
||||
//
|
||||
// randStringBytesMaskImprSrc helps us to generate random paths for the test,
|
||||
// the below piece of code is external, as an answer to a stackoverflow question.
|
||||
//
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"html"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
@ -1041,7 +1040,7 @@ func cacheFiles(ctx stdContext.Context, fs http.FileSystem, names []string, comp
|
|||
|
||||
fi := newFileInfo(path.Base(name), inf.Mode(), inf.ModTime())
|
||||
|
||||
contents, err := ioutil.ReadAll(f)
|
||||
contents, err := io.ReadAll(f)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -6,9 +6,10 @@ import (
|
|||
|
||||
// ExecutionRules gives control to the execution of the route handlers outside of the handlers themselves.
|
||||
// Usage:
|
||||
// Party#SetExecutionRules(ExecutionRules {
|
||||
// Done: ExecutionOptions{Force: true},
|
||||
// })
|
||||
//
|
||||
// Party#SetExecutionRules(ExecutionRules {
|
||||
// Done: ExecutionOptions{Force: true},
|
||||
// })
|
||||
//
|
||||
// See `Party#SetExecutionRules` for more.
|
||||
type ExecutionRules struct {
|
||||
|
|
|
@ -560,9 +560,9 @@ func init() {
|
|||
// system's mime.types file(s) if available under one or more of these
|
||||
// names:
|
||||
//
|
||||
// /etc/mime.types
|
||||
// /etc/apache2/mime.types
|
||||
// /etc/apache/mime.types
|
||||
// /etc/mime.types
|
||||
// /etc/apache2/mime.types
|
||||
// /etc/apache/mime.types
|
||||
//
|
||||
// On Windows, MIME types are extracted from the registry.
|
||||
//
|
||||
|
|
|
@ -491,8 +491,9 @@ func (r *Route) GetTitle() string {
|
|||
// Should be called after `Build` state.
|
||||
//
|
||||
// It prints the @method: @path (@description) (@route_rel_location)
|
||||
// * @handler_name (@handler_rel_location)
|
||||
// * @second_handler ...
|
||||
// - @handler_name (@handler_rel_location)
|
||||
// - @second_handler ...
|
||||
//
|
||||
// If route and handler line:number locations are equal then the second is ignored.
|
||||
func (r *Route) Trace(w io.Writer, stoppedIndex int) {
|
||||
title := r.GetTitle()
|
||||
|
|
21
doc.go
21
doc.go
|
@ -34,34 +34,33 @@ Easy to learn for new gophers and advanced features for experienced, it goes as
|
|||
|
||||
Source code and other details for the project are available at GitHub:
|
||||
|
||||
https://github.com/kataras/iris
|
||||
https://github.com/kataras/iris
|
||||
|
||||
Current Version
|
||||
# Current Version
|
||||
|
||||
12.2.0-beta3
|
||||
12.2.0-beta4
|
||||
|
||||
Installation
|
||||
# Installation
|
||||
|
||||
The only requirement is the Go Programming Language, at least version 1.18.
|
||||
|
||||
$ go get github.com/kataras/iris/v12@master
|
||||
$ go get github.com/kataras/iris/v12@master
|
||||
|
||||
Wiki:
|
||||
|
||||
https://github.com/kataras/iris/wiki
|
||||
https://github.com/kataras/iris/wiki
|
||||
|
||||
Examples:
|
||||
|
||||
https://github.com/kataras/iris/tree/master/_examples
|
||||
https://github.com/kataras/iris/tree/master/_examples
|
||||
|
||||
Middleware:
|
||||
|
||||
https://github.com/kataras/iris/tree/master/middleware
|
||||
https://github.com/iris-contrib/middleware
|
||||
https://github.com/kataras/iris/tree/master/middleware
|
||||
https://github.com/iris-contrib/middleware
|
||||
|
||||
Home Page:
|
||||
|
||||
https://iris-go.com
|
||||
|
||||
https://iris-go.com
|
||||
*/
|
||||
package iris
|
||||
|
|
1
go.mod
1
go.mod
|
@ -15,7 +15,6 @@ require (
|
|||
github.com/fatih/structs v1.1.0
|
||||
github.com/flosch/pongo2/v4 v4.0.2
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/goccy/go-json v0.9.8-0.20220506185958-23bd66f4c0d5
|
||||
github.com/golang/snappy v0.0.4
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/securecookie v1.1.1
|
||||
|
|
2
go.sum
generated
2
go.sum
generated
|
@ -62,8 +62,6 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
|||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
|
||||
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
|
||||
github.com/goccy/go-json v0.9.8-0.20220506185958-23bd66f4c0d5 h1:aeyOtISssR4sP36FAC9LV96PQqxzcbhz54EWv9U+ZGc=
|
||||
github.com/goccy/go-json v0.9.8-0.20220506185958-23bd66f4c0d5/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
|
|
|
@ -326,23 +326,28 @@ func Handler(fn interface{}) context.Handler {
|
|||
// It returns a standard `iris/context.Handler` which can be used anywhere in an Iris Application,
|
||||
// as middleware or as simple route handler or subdomain's handler.
|
||||
//
|
||||
// func(...<T>) iris.Handler
|
||||
// func(...<T>) iris.Handler
|
||||
//
|
||||
// - if <T> are all static dependencies then
|
||||
// there is no reflection involved at serve-time.
|
||||
//
|
||||
// func(pathParameter string, ...<T>)
|
||||
// func(pathParameter string, ...<T>)
|
||||
//
|
||||
// - one or more path parameters (e.g. :uid, :string, :int, :path, :uint64)
|
||||
// are automatically binded to the first input Go standard types (string, int, uint64 and e.t.c.)
|
||||
//
|
||||
// func(<T>) error
|
||||
// func(<T>) error
|
||||
//
|
||||
// - if a function returns an error then this error's text is sent to the client automatically.
|
||||
//
|
||||
// func(<T>) <R>
|
||||
// func(<T>) <R>
|
||||
//
|
||||
// - The result of the function is a dependency too.
|
||||
// If <R> is a request-scope dependency (dynamic) then
|
||||
// this function will be called at every request.
|
||||
//
|
||||
// func(<T>) <R>
|
||||
// func(<T>) <R>
|
||||
//
|
||||
// - If <R> is static dependency (e.g. a database or a service) then its result
|
||||
// can be used as a static dependency to the next dependencies or to the controller/function itself.
|
||||
func (c *Container) Handler(fn interface{}) context.Handler {
|
||||
|
|
|
@ -27,11 +27,9 @@ func defaultResultHandler(ctx *context.Context, v interface{}) error {
|
|||
|
||||
switch context.TrimHeaderValue(ctx.GetContentType()) {
|
||||
case context.ContentXMLHeaderValue, context.ContentXMLUnreadableHeaderValue:
|
||||
_, err := ctx.XML(v)
|
||||
return err
|
||||
return ctx.XML(v)
|
||||
case context.ContentYAMLHeaderValue:
|
||||
_, err := ctx.YAML(v)
|
||||
return err
|
||||
return ctx.YAML(v)
|
||||
case context.ContentProtobufHeaderValue:
|
||||
msg, ok := v.(proto.Message)
|
||||
if !ok {
|
||||
|
@ -45,8 +43,7 @@ func defaultResultHandler(ctx *context.Context, v interface{}) error {
|
|||
return err
|
||||
default:
|
||||
// otherwise default to JSON.
|
||||
_, err := ctx.JSON(v)
|
||||
return err
|
||||
return ctx.JSON(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ func (e err) Dispatch(ctx iris.Context) {
|
|||
// write the status code based on the err's StatusCode.
|
||||
ctx.StatusCode(e.Status)
|
||||
// send to the client the whole object as json
|
||||
_, _ = ctx.JSON(e)
|
||||
_ = ctx.JSON(e)
|
||||
}
|
||||
|
||||
func GetCustomErrorAsDispatcher() err {
|
||||
|
|
|
@ -98,9 +98,12 @@ func DefaultConfiguration() *Configuration {
|
|||
|
||||
// New Prepares and returns a new test framework based on the "app".
|
||||
// Usage:
|
||||
// httptest.New(t, app)
|
||||
//
|
||||
// httptest.New(t, app)
|
||||
//
|
||||
// With options:
|
||||
// httptest.New(t, app, httptest.URL(...), httptest.Debug(true), httptest.LogLevel("debug"), httptest.Strict(true))
|
||||
//
|
||||
// httptest.New(t, app, httptest.URL(...), httptest.Debug(true), httptest.LogLevel("debug"), httptest.Strict(true))
|
||||
//
|
||||
// Example at: https://github.com/kataras/iris/tree/master/_examples/testing/httptest.
|
||||
func New(t *testing.T, app *iris.Application, setters ...OptionSetter) *httpexpect.Expect {
|
||||
|
|
|
@ -152,7 +152,7 @@ func (loc *Locale) Tag() *language.Tag {
|
|||
}
|
||||
|
||||
// Language should return the exact languagecode of this `Locale`
|
||||
//that the user provided on `New` function.
|
||||
// that the user provided on `New` function.
|
||||
//
|
||||
// Same as `Tag().String()` but it's static.
|
||||
func (loc *Locale) Language() string {
|
||||
|
|
|
@ -3,7 +3,7 @@ package i18n
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
|
@ -33,7 +33,7 @@ func Glob(globPattern string, options LoaderConfig) Loader {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
return load(assetNames, ioutil.ReadFile, options)
|
||||
return load(assetNames, os.ReadFile, options)
|
||||
}
|
||||
|
||||
// Assets accepts a function that returns a list of filenames (physical or virtual),
|
||||
|
|
20
iris.go
20
iris.go
|
@ -299,6 +299,7 @@ func (app *Application) ConfigurationReadOnly() context.ConfigurationReadOnly {
|
|||
// Adding one or more outputs : app.Logger().AddOutput(io.Writer...)
|
||||
//
|
||||
// Adding custom levels requires import of the `github.com/kataras/golog` package:
|
||||
//
|
||||
// First we create our level to a golog.Level
|
||||
// in order to be used in the Log functions.
|
||||
// var SuccessLevel golog.Level = 6
|
||||
|
@ -309,6 +310,7 @@ func (app *Application) ConfigurationReadOnly() context.ConfigurationReadOnly {
|
|||
// // ColorfulText (Green Color[SUCC])
|
||||
// ColorfulText: "\x1b[32m[SUCC]\x1b[0m",
|
||||
// }
|
||||
//
|
||||
// Usage:
|
||||
// app.Logger().SetLevel("success")
|
||||
// app.Logger().Logf(SuccessLevel, "a custom leveled log message")
|
||||
|
@ -437,12 +439,12 @@ func (app *Application) GetContextPool() *context.Pool {
|
|||
//
|
||||
// ExampleCode:
|
||||
//
|
||||
// type contextErrorHandler struct{}
|
||||
// func (e *contextErrorHandler) HandleContextError(ctx iris.Context, err error) {
|
||||
// errors.InvalidArgument.Err(ctx, err)
|
||||
// }
|
||||
// ...
|
||||
// app.SetContextErrorHandler(new(contextErrorHandler))
|
||||
// type contextErrorHandler struct{}
|
||||
// func (e *contextErrorHandler) HandleContextError(ctx iris.Context, err error) {
|
||||
// errors.InvalidArgument.Err(ctx, err)
|
||||
// }
|
||||
// ...
|
||||
// app.SetContextErrorHandler(new(contextErrorHandler))
|
||||
func (app *Application) SetContextErrorHandler(errHandler context.ErrorHandler) *Application {
|
||||
app.contextErrorHandler = errHandler
|
||||
return app
|
||||
|
@ -653,9 +655,9 @@ func (app *Application) Shutdown(ctx stdContext.Context) error {
|
|||
//
|
||||
// import "github.com/kataras/iris/v12/core/errgroup"
|
||||
//
|
||||
// errgroup.Walk(app.Build(), func(typ interface{}, err error) {
|
||||
// app.Logger().Errorf("%s: %s", typ, err)
|
||||
// })
|
||||
// errgroup.Walk(app.Build(), func(typ interface{}, err error) {
|
||||
// app.Logger().Errorf("%s: %s", typ, err)
|
||||
// })
|
||||
func (app *Application) Build() error {
|
||||
if app.builded {
|
||||
return nil
|
||||
|
|
|
@ -237,7 +237,7 @@ type (
|
|||
Step3 interface {
|
||||
// Health enables the /health route.
|
||||
// If "env" and "developer" are given, these fields will be populated to the client
|
||||
// through headers and environemnt on health route.
|
||||
// through headers and environment on health route.
|
||||
Health(b bool, env, developer string) Step4
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,9 @@ import (
|
|||
// Note that the builtin macros return error too, but they're handled
|
||||
// by the `else` literal (error code). To change this behavior
|
||||
// and send a custom error response you have to register it:
|
||||
// app.Macros().Get("uuid").HandleError(func(ctx iris.Context, paramIndex int, err error)).
|
||||
//
|
||||
// app.Macros().Get("uuid").HandleError(func(ctx iris.Context, paramIndex int, err error)).
|
||||
//
|
||||
// You can also set custom macros by `app.Macros().Register`.
|
||||
//
|
||||
// See macro.HandleError to set it.
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
|
@ -324,7 +323,7 @@ func BenchmarkAccessLogAfterPrint(b *testing.B) {
|
|||
}
|
||||
|
||||
func benchmarkAccessLogAfter(b *testing.B, withLogStruct, async bool) {
|
||||
ac := New(ioutil.Discard)
|
||||
ac := New(io.Discard)
|
||||
ac.Clock = TClock(time.Time{})
|
||||
ac.BytesReceived = false
|
||||
ac.BytesReceivedBody = false
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
)
|
||||
|
||||
// Log represents the log data specifically for the accesslog middleware.
|
||||
//
|
||||
//easyjson:json
|
||||
type Log struct {
|
||||
// The AccessLog instance this Log was created of.
|
||||
|
|
|
@ -52,8 +52,9 @@ type ErrorHandler func(ctx *context.Context, err error)
|
|||
// The only required value is the Allow field.
|
||||
//
|
||||
// Usage:
|
||||
// opts := Options { ... }
|
||||
// auth := New(opts)
|
||||
//
|
||||
// opts := Options { ... }
|
||||
// auth := New(opts)
|
||||
type Options struct {
|
||||
// Realm directive, read http://tools.ietf.org/html/rfc2617#section-1.2 for details.
|
||||
// E.g. "Authorization Required".
|
||||
|
@ -171,17 +172,18 @@ type BasicAuth struct {
|
|||
// The result should be used to wrap an existing handler or the HTTP application's root router.
|
||||
//
|
||||
// Example Code:
|
||||
// opts := basicauth.Options{
|
||||
// Realm: basicauth.DefaultRealm,
|
||||
// ErrorHandler: basicauth.DefaultErrorHandler,
|
||||
// MaxAge: 2 * time.Hour,
|
||||
// GC: basicauth.GC{
|
||||
// Every: 3 * time.Hour,
|
||||
// },
|
||||
// Allow: basicauth.AllowUsers(users),
|
||||
// }
|
||||
// auth := basicauth.New(opts)
|
||||
// app.Use(auth)
|
||||
//
|
||||
// opts := basicauth.Options{
|
||||
// Realm: basicauth.DefaultRealm,
|
||||
// ErrorHandler: basicauth.DefaultErrorHandler,
|
||||
// MaxAge: 2 * time.Hour,
|
||||
// GC: basicauth.GC{
|
||||
// Every: 3 * time.Hour,
|
||||
// },
|
||||
// Allow: basicauth.AllowUsers(users),
|
||||
// }
|
||||
// auth := basicauth.New(opts)
|
||||
// app.Use(auth)
|
||||
//
|
||||
// Access the user in the route handler with: ctx.User().GetRaw().(*myCustomType).
|
||||
//
|
||||
|
@ -238,16 +240,18 @@ func New(opts Options) context.Handler {
|
|||
// are required as they are compared against the user input
|
||||
// when access to protected resource is requested.
|
||||
// A user list can defined with one of the following values:
|
||||
// map[string]string form of: {username:password, ...}
|
||||
// map[string]interface{} form of: {"username": {"password": "...", "other_field": ...}, ...}
|
||||
// []T which T completes the User interface, where T is a struct value
|
||||
// []T which T contains at least Username and Password fields.
|
||||
//
|
||||
// map[string]string form of: {username:password, ...}
|
||||
// map[string]interface{} form of: {"username": {"password": "...", "other_field": ...}, ...}
|
||||
// []T which T completes the User interface, where T is a struct value
|
||||
// []T which T contains at least Username and Password fields.
|
||||
//
|
||||
// Usage:
|
||||
// auth := Default(map[string]string{
|
||||
// "admin": "admin",
|
||||
// "john": "p@ss",
|
||||
// })
|
||||
//
|
||||
// auth := Default(map[string]string{
|
||||
// "admin": "admin",
|
||||
// "john": "p@ss",
|
||||
// })
|
||||
func Default(users interface{}, userOpts ...UserAuthOption) context.Handler {
|
||||
opts := Options{
|
||||
Realm: DefaultRealm,
|
||||
|
@ -260,7 +264,8 @@ func Default(users interface{}, userOpts ...UserAuthOption) context.Handler {
|
|||
// a filename to load the users from.
|
||||
//
|
||||
// Usage:
|
||||
// auth := Load("users.yml")
|
||||
//
|
||||
// auth := Load("users.yml")
|
||||
func Load(jsonOrYamlFilename string, userOpts ...UserAuthOption) context.Handler {
|
||||
opts := Options{
|
||||
Realm: DefaultRealm,
|
||||
|
|
|
@ -3,7 +3,7 @@ package basicauth
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
|
@ -16,8 +16,8 @@ import (
|
|||
// ReadFile can be used to customize the way the
|
||||
// AllowUsersFile function is loading the filename from.
|
||||
// Example of usage: embedded users.yml file.
|
||||
// Defaults to the `ioutil.ReadFile` which reads the file from the physical disk.
|
||||
var ReadFile = ioutil.ReadFile
|
||||
// Defaults to the `os.ReadFile` which reads the file from the physical disk.
|
||||
var ReadFile = os.ReadFile
|
||||
|
||||
// User is a partial part of the iris.User interface.
|
||||
// It's used to declare a static slice of registered User for authentication.
|
||||
|
@ -48,10 +48,11 @@ type UserAuthOption func(*UserAuthOptions)
|
|||
// See https://www.usenix.org/legacy/event/usenix99/provos/provos.pdf.
|
||||
//
|
||||
// Usage:
|
||||
// Default(..., BCRYPT) OR
|
||||
// Load(..., BCRYPT) OR
|
||||
// Options.Allow = AllowUsers(..., BCRYPT) OR
|
||||
// OPtions.Allow = AllowUsersFile(..., BCRYPT)
|
||||
//
|
||||
// Default(..., BCRYPT) OR
|
||||
// Load(..., BCRYPT) OR
|
||||
// Options.Allow = AllowUsers(..., BCRYPT) OR
|
||||
// OPtions.Allow = AllowUsersFile(..., BCRYPT)
|
||||
func BCRYPT(opts *UserAuthOptions) {
|
||||
opts.ComparePassword = func(stored, userPassword string) bool {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(stored), []byte(userPassword))
|
||||
|
@ -75,10 +76,11 @@ func toUserAuthOptions(opts []UserAuthOption) (options UserAuthOptions) {
|
|||
|
||||
// AllowUsers is an AuthFunc which authenticates user input based on a (static) user list.
|
||||
// The "users" input parameter can be one of the following forms:
|
||||
// map[string]string e.g. {username: password, username: password...}.
|
||||
// []map[string]interface{} e.g. []{"username": "...", "password": "...", "other_field": ...}, ...}.
|
||||
// []T which T completes the User interface.
|
||||
// []T which T contains at least Username and Password fields.
|
||||
//
|
||||
// map[string]string e.g. {username: password, username: password...}.
|
||||
// []map[string]interface{} e.g. []{"username": "...", "password": "...", "other_field": ...}, ...}.
|
||||
// []T which T completes the User interface.
|
||||
// []T which T contains at least Username and Password fields.
|
||||
//
|
||||
// Usage:
|
||||
// New(Options{Allow: AllowUsers(..., [BCRYPT])})
|
||||
|
@ -155,15 +157,17 @@ func userMap(usernamePassword map[string]string, opts ...UserAuthOption) AuthFun
|
|||
// loaded from a file on initialization.
|
||||
//
|
||||
// Example Code:
|
||||
// New(Options{Allow: AllowUsersFile("users.yml", BCRYPT)})
|
||||
//
|
||||
// New(Options{Allow: AllowUsersFile("users.yml", BCRYPT)})
|
||||
//
|
||||
// The users.yml file looks like the following:
|
||||
// - username: kataras
|
||||
// password: kataras_pass
|
||||
// age: 27
|
||||
// role: admin
|
||||
// - username: makis
|
||||
// password: makis_password
|
||||
// ...
|
||||
// - username: kataras
|
||||
// password: kataras_pass
|
||||
// age: 27
|
||||
// role: admin
|
||||
// - username: makis
|
||||
// password: makis_password
|
||||
// ...
|
||||
func AllowUsersFile(jsonOrYamlFilename string, opts ...UserAuthOption) AuthFunc {
|
||||
var (
|
||||
usernamePassword map[string]string
|
||||
|
|
|
@ -2,7 +2,6 @@ package basicauth
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
@ -164,7 +163,7 @@ func TestAllowUsers(t *testing.T) {
|
|||
|
||||
// Test YAML user loading with b-encrypted passwords.
|
||||
func TestAllowUsersFile(t *testing.T) {
|
||||
f, err := ioutil.TempFile("", "*users.yml")
|
||||
f, err := os.CreateTemp("", "*users.yml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -85,17 +85,18 @@ type (
|
|||
// please refer to: https://github.com/iris-contrib/middleware repository instead.
|
||||
//
|
||||
// Example Code:
|
||||
// import "github.com/kataras/iris/v12/middleware/cors"
|
||||
// import "github.com/kataras/iris/v12/x/errors"
|
||||
//
|
||||
// app.UseRouter(cors.New().
|
||||
// HandleErrorFunc(func(ctx iris.Context, err error) {
|
||||
// errors.FailedPrecondition.Err(ctx, err)
|
||||
// }).
|
||||
// ExtractOriginFunc(cors.StrictOriginExtractor).
|
||||
// ReferrerPolicy(cors.NoReferrerWhenDowngrade).
|
||||
// AllowOrigin("domain1.com,domain2.com,domain3.com").
|
||||
// Handler())
|
||||
// import "github.com/kataras/iris/v12/middleware/cors"
|
||||
// import "github.com/kataras/iris/v12/x/errors"
|
||||
//
|
||||
// app.UseRouter(cors.New().
|
||||
// HandleErrorFunc(func(ctx iris.Context, err error) {
|
||||
// errors.FailedPrecondition.Err(ctx, err)
|
||||
// }).
|
||||
// ExtractOriginFunc(cors.StrictOriginExtractor).
|
||||
// ReferrerPolicy(cors.NoReferrerWhenDowngrade).
|
||||
// AllowOrigin("domain1.com,domain2.com,domain3.com").
|
||||
// Handler())
|
||||
func New() *CORS {
|
||||
return &CORS{
|
||||
extractOriginFunc: DefaultOriginExtractor,
|
||||
|
|
|
@ -13,11 +13,12 @@ import (
|
|||
// The Iris server SHOULD run under HTTP/2 and clients too.
|
||||
//
|
||||
// Usage:
|
||||
// import grpcWrapper "github.com/kataras/iris/v12/middleware/grpc"
|
||||
// [...]
|
||||
// app := iris.New()
|
||||
// grpcServer := grpc.NewServer()
|
||||
// app.WrapRouter(grpcWrapper.New(grpcServer))
|
||||
//
|
||||
// import grpcWrapper "github.com/kataras/iris/v12/middleware/grpc"
|
||||
// [...]
|
||||
// app := iris.New()
|
||||
// grpcServer := grpc.NewServer()
|
||||
// app.WrapRouter(grpcWrapper.New(grpcServer))
|
||||
func New(grpcServer http.Handler) router.WrapperFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request, mux http.HandlerFunc) {
|
||||
if r.ProtoMajor == 2 && strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc") {
|
||||
|
|
|
@ -3,7 +3,7 @@ package hcaptcha
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
|
@ -70,7 +70,9 @@ func New(secret string, options ...Option) context.Handler {
|
|||
|
||||
// Handler is the HTTP route middleware featured hcaptcha validation.
|
||||
// It calls the `SiteVerify` method and fires the "next" when user completed the hcaptcha successfully,
|
||||
// otherwise it calls the Client's `FailureHandler`.
|
||||
//
|
||||
// otherwise it calls the Client's `FailureHandler`.
|
||||
//
|
||||
// The hcaptcha's `Response` (which contains any `ErrorCodes`)
|
||||
// is saved on the Request's Context (see `GetResponseFromContext`).
|
||||
func (c *Client) Handler(ctx *context.Context) {
|
||||
|
@ -113,7 +115,7 @@ func SiteVerify(ctx *context.Context, secret string) (response Response) {
|
|||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
response.ErrorCodes = append(response.ErrorCodes, err.Error())
|
||||
|
|
|
@ -55,14 +55,14 @@ var _ jwt.Blocklist = (*Blocklist)(nil)
|
|||
//
|
||||
// Usage:
|
||||
//
|
||||
// blocklist := NewBlocklist()
|
||||
// blocklist.ClientOptions.Addr = ...
|
||||
// err := blocklist.Connect()
|
||||
// blocklist := NewBlocklist()
|
||||
// blocklist.ClientOptions.Addr = ...
|
||||
// err := blocklist.Connect()
|
||||
//
|
||||
// And register it:
|
||||
//
|
||||
// verifier := jwt.NewVerifier(...)
|
||||
// verifier.Blocklist = blocklist
|
||||
// verifier := jwt.NewVerifier(...)
|
||||
// verifier.Blocklist = blocklist
|
||||
func NewBlocklist() *Blocklist {
|
||||
return &Blocklist{
|
||||
GetKey: defaultGetKey,
|
||||
|
|
|
@ -31,8 +31,8 @@ type Signer struct {
|
|||
//
|
||||
// Usage:
|
||||
//
|
||||
// signer := NewSigner(HS256, secret, 15*time.Minute)
|
||||
// token, err := signer.Sign(userClaims{Username: "kataras"})
|
||||
// signer := NewSigner(HS256, secret, 15*time.Minute)
|
||||
// token, err := signer.Sign(userClaims{Username: "kataras"})
|
||||
func NewSigner(signatureAlg Alg, signatureKey interface{}, maxAge time.Duration) *Signer {
|
||||
if signatureAlg == HS256 {
|
||||
// A tiny helper if the end-developer uses string instead of []byte for hmac keys.
|
||||
|
|
|
@ -61,24 +61,31 @@ type Verifier struct {
|
|||
//
|
||||
// Usage:
|
||||
//
|
||||
// verifier := NewVerifier(HS256, secret)
|
||||
// OR
|
||||
// verifier := NewVerifier(HS256, secret, Expected{Issuer: "my-app"})
|
||||
// verifier := NewVerifier(HS256, secret)
|
||||
//
|
||||
// claimsGetter := func() interface{} { return new(userClaims) }
|
||||
// middleware := verifier.Verify(claimsGetter)
|
||||
// OR
|
||||
// middleware := verifier.Verify(claimsGetter, Expected{Issuer: "my-app"})
|
||||
//
|
||||
// verifier := NewVerifier(HS256, secret, Expected{Issuer: "my-app"})
|
||||
//
|
||||
// claimsGetter := func() interface{} { return new(userClaims) }
|
||||
// middleware := verifier.Verify(claimsGetter)
|
||||
//
|
||||
// OR
|
||||
//
|
||||
// middleware := verifier.Verify(claimsGetter, Expected{Issuer: "my-app"})
|
||||
//
|
||||
// Register the middleware, e.g.
|
||||
// app.Use(middleware)
|
||||
//
|
||||
// app.Use(middleware)
|
||||
//
|
||||
// Get the claims:
|
||||
// claims := jwt.Get(ctx).(*userClaims)
|
||||
// username := claims.Username
|
||||
//
|
||||
// claims := jwt.Get(ctx).(*userClaims)
|
||||
// username := claims.Username
|
||||
//
|
||||
// Get the context user:
|
||||
// username, err := ctx.User().GetUsername()
|
||||
//
|
||||
// username, err := ctx.User().GetUsername()
|
||||
func NewVerifier(signatureAlg Alg, signatureKey interface{}, validators ...TokenValidator) *Verifier {
|
||||
if signatureAlg == HS256 {
|
||||
// A tiny helper if the end-developer uses string instead of []byte for hmac keys.
|
||||
|
|
|
@ -166,11 +166,12 @@ func Query(paramName string) Option {
|
|||
// to determinate the method to override with.
|
||||
//
|
||||
// Use cases:
|
||||
// 1. When need to check only for headers and ignore other fields:
|
||||
// New(Only(Headers("X-Custom-Header")))
|
||||
//
|
||||
// 2. When need to check only for (first) form field and (second) custom getter:
|
||||
// New(Only(FormField("fieldName"), Getter(...)))
|
||||
// 1. When need to check only for headers and ignore other fields:
|
||||
// New(Only(Headers("X-Custom-Header")))
|
||||
//
|
||||
// 2. When need to check only for (first) form field and (second) custom getter:
|
||||
// New(Only(FormField("fieldName"), Getter(...)))
|
||||
func Only(o ...Option) Option {
|
||||
return func(opts *options) {
|
||||
opts.getters = opts.getters[0:0]
|
||||
|
@ -185,7 +186,6 @@ func Only(o ...Option) Option {
|
|||
// that do not support certain HTTP operations such as DELETE or PUT for security reasons.
|
||||
// This wrapper will accept a method, based on criteria, to override the POST method with.
|
||||
//
|
||||
//
|
||||
// Read more at:
|
||||
// https://github.com/kataras/iris/issues/1325
|
||||
func New(opt ...Option) router.WrapperFunc {
|
||||
|
|
|
@ -34,12 +34,13 @@ type Options struct {
|
|||
// for security reasons.
|
||||
//
|
||||
// Example Code:
|
||||
// app.Get("/health", modrevision.New(modrevision.Options{
|
||||
// ServerName: "Iris Server",
|
||||
// Env: "development",
|
||||
// Developer: "kataras",
|
||||
// TimeLocation: time.FixedZone("Greece/Athens", 10800),
|
||||
// }))
|
||||
//
|
||||
// app.Get("/health", modrevision.New(modrevision.Options{
|
||||
// ServerName: "Iris Server",
|
||||
// Env: "development",
|
||||
// Developer: "kataras",
|
||||
// TimeLocation: time.FixedZone("Greece/Athens", 7200),
|
||||
// }))
|
||||
func New(opts Options) context.Handler {
|
||||
buildTime, buildRevision := context.BuildTime, context.BuildRevision
|
||||
if opts.UnixTime {
|
||||
|
|
|
@ -41,7 +41,8 @@ var profileDescriptions = map[string]string{
|
|||
// New returns a new pprof (profile, cmdline, symbol, goroutine, heap, threadcreate, debug/block) Middleware.
|
||||
// Note: Route MUST have the last named parameter wildcard named '{action:path}'.
|
||||
// Example:
|
||||
// app.HandleMany("GET", "/debug/pprof /debug/pprof/{action:path}", pprof.New())
|
||||
//
|
||||
// app.HandleMany("GET", "/debug/pprof /debug/pprof/{action:path}", pprof.New())
|
||||
func New() context.Handler {
|
||||
return func(ctx *context.Context) {
|
||||
if action := ctx.Params().Get("action"); action != "" {
|
||||
|
|
|
@ -3,7 +3,7 @@ package recaptcha
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
|
@ -50,7 +50,9 @@ func New(secret string) context.Handler {
|
|||
}
|
||||
|
||||
// SiteVerify accepts context and the secret key(https://www.google.com/recaptcha)
|
||||
// and returns the google's recaptcha response, if `response.Success` is true
|
||||
//
|
||||
// and returns the google's recaptcha response, if `response.Success` is true
|
||||
//
|
||||
// then validation passed.
|
||||
//
|
||||
// Use `New` for middleware use instead.
|
||||
|
@ -74,7 +76,7 @@ func SiteVerify(ctx *context.Context, secret string) (response Response) {
|
|||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
body, err := io.ReadAll(r.Body)
|
||||
r.Body.Close()
|
||||
if err != nil {
|
||||
response.ErrorCodes = append(response.ErrorCodes, err.Error())
|
||||
|
@ -113,22 +115,24 @@ var recaptchaForm = `<form action="%s" method="POST">
|
|||
// Example Code:
|
||||
//
|
||||
// Method: "POST" | Path: "/contact"
|
||||
// func postContact(ctx *context.Context) {
|
||||
// // [...]
|
||||
// response := recaptcha.SiteVerify(ctx, recaptchaSecret)
|
||||
//
|
||||
// if response.Success {
|
||||
// // [your action here, i.e sendEmail(...)]
|
||||
// }
|
||||
// func postContact(ctx *context.Context) {
|
||||
// // [...]
|
||||
// response := recaptcha.SiteVerify(ctx, recaptchaSecret)
|
||||
//
|
||||
// ctx.JSON(response)
|
||||
// }
|
||||
// if response.Success {
|
||||
// // [your action here, i.e sendEmail(...)]
|
||||
// }
|
||||
//
|
||||
// ctx.JSON(response)
|
||||
// }
|
||||
//
|
||||
// Method: "GET" | Path: "/contact"
|
||||
// func getContact(ctx *context.Context) {
|
||||
// // render the recaptcha form
|
||||
// ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, "/contact"))
|
||||
// }
|
||||
//
|
||||
// func getContact(ctx *context.Context) {
|
||||
// // render the recaptcha form
|
||||
// ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, "/contact"))
|
||||
// }
|
||||
func GetFormHTML(dataSiteKey string, postActionRelativePath string) string {
|
||||
return fmt.Sprintf(recaptchaForm, postActionRelativePath, dataSiteKey)
|
||||
}
|
||||
|
|
|
@ -384,9 +384,11 @@ func (c *ControllerActivator) handleHTTPError(funcName string) *router.Route {
|
|||
//
|
||||
// Just like `Party#HandleMany`:, it returns the `[]*router.Routes`.
|
||||
// Usage:
|
||||
// func (*Controller) BeforeActivation(b mvc.BeforeActivation) {
|
||||
// b.HandleMany("GET", "/path /path1" /path2", "HandlePath")
|
||||
// }
|
||||
//
|
||||
// func (*Controller) BeforeActivation(b mvc.BeforeActivation) {
|
||||
// b.HandleMany("GET", "/path /path1" /path2", "HandlePath")
|
||||
// }
|
||||
//
|
||||
// HandleMany will override any routes of this "funcName".
|
||||
func (c *ControllerActivator) HandleMany(method, path, funcName string, middleware ...context.Handler) []*router.Route {
|
||||
return c.handleMany(method, path, funcName, true, middleware...)
|
||||
|
|
|
@ -86,7 +86,8 @@ func New(party router.Party) *Application {
|
|||
// this function simply calls the `New(party)` and its `.Configure(configurators...)`.
|
||||
//
|
||||
// A call of `mvc.New(app.Party("/path").Configure(buildMyMVC)` is equal to
|
||||
// `mvc.Configure(app.Party("/path"), buildMyMVC)`.
|
||||
//
|
||||
// `mvc.Configure(app.Party("/path"), buildMyMVC)`.
|
||||
//
|
||||
// Read more at `New() Application` and `Application#Configure` methods.
|
||||
func Configure(party router.Party, configurators ...func(*Application)) *Application {
|
||||
|
|
|
@ -10,13 +10,13 @@ import (
|
|||
// It requires a specific "version" constraint for a Controller,
|
||||
// e.g. ">1.0.0 <=2.0.0".
|
||||
//
|
||||
//
|
||||
// Usage:
|
||||
// m := mvc.New(dataRouter)
|
||||
// m.Handle(new(v1Controller), mvc.Version("1.0.0"), mvc.Deprecated(mvc.DeprecationOptions{}))
|
||||
// m.Handle(new(v2Controller), mvc.Version("2.3.0"))
|
||||
// m.Handle(new(v3Controller), mvc.Version(">=3.0.0 <4.0.0"))
|
||||
// m.Handle(new(noVersionController))
|
||||
//
|
||||
// m := mvc.New(dataRouter)
|
||||
// m.Handle(new(v1Controller), mvc.Version("1.0.0"), mvc.Deprecated(mvc.DeprecationOptions{}))
|
||||
// m.Handle(new(v2Controller), mvc.Version("2.3.0"))
|
||||
// m.Handle(new(v3Controller), mvc.Version(">=3.0.0 <4.0.0"))
|
||||
// m.Handle(new(noVersionController))
|
||||
//
|
||||
// See the `versioning` package's documentation for more information on
|
||||
// how the version is extracted from incoming requests.
|
||||
|
|
|
@ -78,8 +78,13 @@ func (c Config) Validate() Config {
|
|||
}
|
||||
|
||||
if c.SessionIDGenerator == nil {
|
||||
c.SessionIDGenerator = func(*context.Context) string {
|
||||
id, _ := uuid.NewRandom()
|
||||
c.SessionIDGenerator = func(ctx *context.Context) string {
|
||||
id, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
ctx.StopWithError(400, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return id.String()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,24 +94,28 @@ func (s *mem) OnUpdateExpiration(string, time.Duration) error { return nil }
|
|||
// immutable depends on the store, it may not implement it at all.
|
||||
func (s *mem) Set(sid string, key string, value interface{}, _ time.Duration, immutable bool) error {
|
||||
s.mu.RLock()
|
||||
s.values[sid].Save(key, value, immutable)
|
||||
store, ok := s.values[sid]
|
||||
s.mu.RUnlock()
|
||||
if ok {
|
||||
store.Save(key, value, immutable)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *mem) Get(sid string, key string) interface{} {
|
||||
s.mu.RLock()
|
||||
v := s.values[sid].Get(key)
|
||||
store, ok := s.values[sid]
|
||||
s.mu.RUnlock()
|
||||
if ok {
|
||||
return store.Get(key)
|
||||
}
|
||||
|
||||
return v
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *mem) Decode(sid string, key string, outPtr interface{}) error {
|
||||
s.mu.RLock()
|
||||
v := s.values[sid].Get(key)
|
||||
s.mu.RUnlock()
|
||||
v := s.Get(sid, key)
|
||||
if v != nil {
|
||||
reflect.ValueOf(outPtr).Set(reflect.ValueOf(v))
|
||||
}
|
||||
|
@ -119,29 +123,45 @@ func (s *mem) Decode(sid string, key string, outPtr interface{}) error {
|
|||
}
|
||||
|
||||
func (s *mem) Visit(sid string, cb func(key string, value interface{})) error {
|
||||
s.values[sid].Visit(cb)
|
||||
s.mu.RLock()
|
||||
store, ok := s.values[sid]
|
||||
s.mu.RUnlock()
|
||||
if ok {
|
||||
store.Visit(cb)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *mem) Len(sid string) int {
|
||||
s.mu.RLock()
|
||||
n := s.values[sid].Len()
|
||||
store, ok := s.values[sid]
|
||||
s.mu.RUnlock()
|
||||
if ok {
|
||||
return store.Len()
|
||||
}
|
||||
|
||||
return n
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *mem) Delete(sid string, key string) (deleted bool) {
|
||||
s.mu.RLock()
|
||||
deleted = s.values[sid].Remove(key)
|
||||
store, ok := s.values[sid]
|
||||
s.mu.RUnlock()
|
||||
if ok {
|
||||
deleted = store.Remove(key)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *mem) Clear(sid string) error {
|
||||
s.mu.Lock()
|
||||
s.values[sid].Reset()
|
||||
s.mu.Unlock()
|
||||
s.mu.RLock()
|
||||
store, ok := s.values[sid]
|
||||
s.mu.RUnlock()
|
||||
if ok {
|
||||
store.Reset()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -150,7 +170,6 @@ func (s *mem) Release(sid string) error {
|
|||
s.mu.Lock()
|
||||
delete(s.values, sid)
|
||||
s.mu.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@ func (p *provider) newSession(man *Sessions, sid string, expires time.Duration)
|
|||
sid: sid,
|
||||
Man: man,
|
||||
provider: p,
|
||||
flashes: make(map[string]*flashMessage),
|
||||
}
|
||||
|
||||
onExpire := func() {
|
||||
|
@ -99,9 +98,10 @@ func (p *provider) EndRequest(ctx *context.Context, session *Session) {
|
|||
// ErrNotFound may be returned from `UpdateExpiration` of a non-existing or
|
||||
// invalid session entry from memory storage or databases.
|
||||
// Usage:
|
||||
// if err != nil && err.Is(err, sessions.ErrNotFound) {
|
||||
// [handle error...]
|
||||
// }
|
||||
//
|
||||
// if err != nil && err.Is(err, sessions.ErrNotFound) {
|
||||
// [handle error...]
|
||||
// }
|
||||
var ErrNotFound = errors.New("session not found")
|
||||
|
||||
// UpdateExpiration resets the expiration of a session.
|
||||
|
|
|
@ -76,6 +76,7 @@ func (s *Session) runFlashGC() {
|
|||
delete(s.flashes, key)
|
||||
}
|
||||
}
|
||||
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
|
@ -558,6 +559,10 @@ func (s *Session) SetImmutable(key string, value interface{}) {
|
|||
// If you want to define more than one flash messages, you will have to use different keys.
|
||||
func (s *Session) SetFlash(key string, value interface{}) {
|
||||
s.mu.Lock()
|
||||
if s.flashes == nil {
|
||||
s.flashes = make(map[string]*flashMessage)
|
||||
}
|
||||
|
||||
s.flashes[key] = &flashMessage{value: value}
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ func testSessions(t *testing.T, app *iris.Application) {
|
|||
s := sessions.Get(ctx)
|
||||
sessValues := s.GetAll()
|
||||
|
||||
_, err := ctx.JSON(sessValues)
|
||||
err := ctx.JSON(sessValues)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -141,8 +141,7 @@ func TestFlashMessages(t *testing.T) {
|
|||
}
|
||||
|
||||
writeValues := func(ctx *context.Context, values map[string]interface{}) error {
|
||||
_, err := ctx.JSON(values)
|
||||
return err
|
||||
return ctx.JSON(values)
|
||||
}
|
||||
|
||||
app.Post("/set", func(ctx *context.Context) {
|
||||
|
|
|
@ -30,25 +30,31 @@ type Group struct {
|
|||
// any changes to its parent won't affect this one (e.g. register global middlewares afterwards).
|
||||
//
|
||||
// A version is extracted through the versioning.GetVersion function:
|
||||
// Accept-Version: 1.0.0
|
||||
// Accept: application/json; version=1.0.0
|
||||
// You can customize it by setting a version based on the request context:
|
||||
// api.Use(func(ctx *context.Context) {
|
||||
// if version := ctx.URLParam("version"); version != "" {
|
||||
// SetVersion(ctx, version)
|
||||
// }
|
||||
//
|
||||
// ctx.Next()
|
||||
// })
|
||||
// Accept-Version: 1.0.0
|
||||
// Accept: application/json; version=1.0.0
|
||||
//
|
||||
// You can customize it by setting a version based on the request context:
|
||||
//
|
||||
// api.Use(func(ctx *context.Context) {
|
||||
// if version := ctx.URLParam("version"); version != "" {
|
||||
// SetVersion(ctx, version)
|
||||
// }
|
||||
//
|
||||
// ctx.Next()
|
||||
// })
|
||||
//
|
||||
// OR:
|
||||
// api.Use(versioning.FromQuery("version", ""))
|
||||
//
|
||||
// api.Use(versioning.FromQuery("version", ""))
|
||||
//
|
||||
// Examples at: _examples/routing/versioning
|
||||
// Usage:
|
||||
// app := iris.New()
|
||||
// api := app.Party("/api")
|
||||
// v1 := versioning.NewGroup(api, ">=1.0.0 <2.0.0")
|
||||
// v1.Get/Post/Put/Delete...
|
||||
//
|
||||
// app := iris.New()
|
||||
// api := app.Party("/api")
|
||||
// v1 := versioning.NewGroup(api, ">=1.0.0 <2.0.0")
|
||||
// v1.Get/Post/Put/Delete...
|
||||
//
|
||||
// Valid ranges are:
|
||||
// - "<1.0.0"
|
||||
|
@ -61,8 +67,10 @@ type Group struct {
|
|||
// A Range can consist of multiple ranges separated by space:
|
||||
// Ranges can be linked by logical AND:
|
||||
// - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7"
|
||||
//
|
||||
// but not "1.0.0" or "2.0.0"
|
||||
// - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0
|
||||
//
|
||||
// except 2.0.3-beta.2
|
||||
//
|
||||
// Ranges can also be linked by logical OR:
|
||||
|
@ -72,7 +80,8 @@ type Group struct {
|
|||
//
|
||||
// Ranges can be combined by both AND and OR
|
||||
//
|
||||
// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`,
|
||||
// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`,
|
||||
//
|
||||
// but not `4.2.1`, `2.1.1`
|
||||
func NewGroup(r API, version string) *Group {
|
||||
version = strings.ReplaceAll(version, ",", " ")
|
||||
|
|
|
@ -187,11 +187,13 @@ func GetVersion(ctx *context.Context) string {
|
|||
// It can be used inside a middleware.
|
||||
// Example of how you can change the default behavior to extract a requested version (which is by headers)
|
||||
// from a "version" url parameter instead:
|
||||
// func(ctx iris.Context) { // &version=1
|
||||
// version := ctx.URLParamDefault("version", "1.0.0")
|
||||
// versioning.SetVersion(ctx, version)
|
||||
// ctx.Next()
|
||||
// }
|
||||
//
|
||||
// func(ctx iris.Context) { // &version=1
|
||||
// version := ctx.URLParamDefault("version", "1.0.0")
|
||||
// versioning.SetVersion(ctx, version)
|
||||
// ctx.Next()
|
||||
// }
|
||||
//
|
||||
// See `GetVersion` too.
|
||||
func SetVersion(ctx *context.Context, constraint string) {
|
||||
ctx.Values().Set(ctx.Application().ConfigurationReadOnly().GetVersionContextKey(), constraint)
|
||||
|
@ -205,23 +207,24 @@ type AliasMap = map[string]string
|
|||
// for the children Parties(routers). It's respected by versioning Groups.
|
||||
//
|
||||
// Example Code:
|
||||
// app := iris.New()
|
||||
//
|
||||
// api := app.Party("/api")
|
||||
// api.Use(Aliases(map[string]string{
|
||||
// versioning.Empty: "1.0.0", // when no version was provided by the client.
|
||||
// "beta": "4.0.0",
|
||||
// "stage": "5.0.0-alpha"
|
||||
// }))
|
||||
// app := iris.New()
|
||||
//
|
||||
// v1 := NewGroup(api, ">=1.0.0 < 2.0.0")
|
||||
// v1.Get/Post...
|
||||
// api := app.Party("/api")
|
||||
// api.Use(Aliases(map[string]string{
|
||||
// versioning.Empty: "1.0.0", // when no version was provided by the client.
|
||||
// "beta": "4.0.0",
|
||||
// "stage": "5.0.0-alpha"
|
||||
// }))
|
||||
//
|
||||
// v4 := NewGroup(api, ">=4.0.0 < 5.0.0")
|
||||
// v4.Get/Post...
|
||||
// v1 := NewGroup(api, ">=1.0.0 < 2.0.0")
|
||||
// v1.Get/Post...
|
||||
//
|
||||
// stage := NewGroup(api, "5.0.0-alpha")
|
||||
// stage.Get/Post...
|
||||
// v4 := NewGroup(api, ">=4.0.0 < 5.0.0")
|
||||
// v4.Get/Post...
|
||||
//
|
||||
// stage := NewGroup(api, "5.0.0-alpha")
|
||||
// stage.Get/Post...
|
||||
func Aliases(aliases AliasMap) context.Handler {
|
||||
cp := make(AliasMap, len(aliases)) // copy the map here so we are safe of later modifications by end-dev.
|
||||
for k, v := range aliases {
|
||||
|
|
|
@ -50,7 +50,8 @@ type (
|
|||
// through a Context or within filter functions.
|
||||
//
|
||||
// Example:
|
||||
// AsValue("my string")
|
||||
//
|
||||
// AsValue("my string")
|
||||
//
|
||||
// Shortcut for `pongo2.AsValue`.
|
||||
var AsValue = pongo2.AsValue
|
||||
|
|
|
@ -2,7 +2,7 @@ package view
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
@ -80,7 +80,7 @@ func asset(fs http.FileSystem, name string) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
contents, err := ioutil.ReadAll(f)
|
||||
contents, err := io.ReadAll(f)
|
||||
f.Close()
|
||||
return contents, err
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user