diff --git a/HISTORY.md b/HISTORY.md
index a850939b..ada11bab 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -448,7 +448,7 @@ New Package-level Variables:
- `iris.DirListRichOptions` to pass on `iris.DirListRich` method.
- `iris.DirListRich` to override the default look and feel if the `DirOptions.ShowList` was set to true, can be passed to `DirOptions.DirList` field.
- `DirOptions.PushTargets` for http/2 push on index [*](https://github.com/kataras/iris/tree/master/_examples/file-server/http2push/main.go).
-- `iris.Compress` and `iris.CompressReader` middleware to compress responses and decode compressed request data respectfully.
+- `iris.Compression` middleware to compress responses and decode compressed request data respectfully.
- `iris.B, KB, MB, GB, TB, PB, EB` for byte units.
- `TLSNoRedirect` to disable automatic "http://" to "https://" redirections (see below)
- `CookieAllowReclaim`, `CookieAllowSubdomains`, `CookieSameSite`, `CookieSecure` and `CookieEncoding` to bring previously sessions-only features to all cookies in the request.
@@ -456,7 +456,7 @@ New Package-level Variables:
New Context Methods:
- `Context.SetErr(error)` and `Context.GetErr() error` helpers
-- `Context.Compress(bool) error` and `Context.CompressReader(bool) error`
+- `Context.CompressWriter(bool) error` and `Context.CompressReader(bool) error`
- `Context.Clone() Context` returns a copy of the Context.
- `Context.IsCanceled() bool` reports whether the request has been canceled by the client.
- `Context.IsSSL() bool` reports whether the request is under HTTPS SSL (New `Configuration.SSLProxyHeaders` and `HostProxyHeaders` fields too).
@@ -487,10 +487,9 @@ New Context Methods:
Breaking Changes:
-- `ctx.Gzip(boolean)` replaced with `ctx.Compress(boolean) error`.
+- `ctx.Gzip(boolean)` replaced with `ctx.CompressWriter(boolean) error`.
- `ctx.GzipReader(boolean) error` replaced with `ctx.CompressReader(boolean) error`.
-- `iris.Gzip` replaced with `iris.Compress` (middleware).
-- `iris.GzipReader` replaced with `iris.CompressReader` (middleware).
+- `iris.Gzip` and `iris.GzipReader` replaced with `iris.Compression` (middleware).
- `ctx.ClientSupportsGzip() bool` replaced with `ctx.ClientSupportsEncoding("gzip", "br" ...) bool`.
- `ctx.GzipResponseWriter()` is **removed**.
- `Party.HandleDir` now returns a list of `[]*Route` (GET and HEAD) instead of GET only.
@@ -502,7 +501,7 @@ Breaking Changes:
- `sessions#Config.Encode` and `Decode` are removed in favor of (the existing) `Encoding` field.
- `versioning.GetVersion` now returns an empty string if version wasn't found.
- Change the MIME type of `Javascript .js` and `JSONP` as the HTML specification now recommends to `"text/javascript"` instead of the obselete `"application/javascript"`. This change was pushed to the `Go` language itself as well. See .
-- Remove the last input argument of `enableGzipCompression` in `Context.ServeContent`, `ServeFile` methods. This was deprecated a few versions ago. A middleware (`app.Use(iris.Compress)`) or a prior call to `Context.Compress(true)` will enable compression. Also these two methods and `Context.SendFile` one now support `Content-Range` and `Accept-Ranges` correctly out of the box (`net/http` had a bug, which is now fixed).
+- Remove the last input argument of `enableGzipCompression` in `Context.ServeContent`, `ServeFile` methods. This was deprecated a few versions ago. A middleware (`app.Use(iris.CompressWriter)`) or a prior call to `Context.CompressWriter(true)` will enable compression. Also these two methods and `Context.SendFile` one now support `Content-Range` and `Accept-Ranges` correctly out of the box (`net/http` had a bug, which is now fixed).
- `Context.ServeContent` no longer returns an error, see `ServeContentWithRate`, `ServeFileWithRate` and `SendFileWithRate` new methods too.
- `route.Trace() string` changed to `route.Trace(w io.Writer)`, to achieve the same result just pass a `bytes.Buffer`
- `var mvc.AutoBinding` removed as the default behavior now resolves such dependencies automatically (see [[FEATURE REQUEST] MVC serving gRPC-compatible controller](https://github.com/kataras/iris/issues/1449)).
diff --git a/README.md b/README.md
index 033c3c4f..67c30f6c 100644
--- a/README.md
+++ b/README.md
@@ -26,9 +26,6 @@ Learn what [others saying about Iris](https://iris-go.com/testimonials/) and **[
## 📖 Learning Iris
-
-Quick start
-
```sh
# https://github.com/kataras/iris/wiki/Installation
$ go get github.com/kataras/iris/v12@master
@@ -42,18 +39,110 @@ package main
import "github.com/kataras/iris/v12"
func main() {
- app := iris.New()
- app.Get("/", index)
- app.Listen(":8080")
+ app := iris.New()
+
+ booksAPI := app.Party("/books")
+ {
+ booksAPI.Use(iris.Compression)
+
+ // GET: http://localhost:8080/books
+ booksAPI.Get("/", list)
+ // POST: http://localhost:8080/books
+ booksAPI.Post("/", create)
+ }
+
+ app.Listen(":8080")
}
-func index(ctx iris.Context) {
- ctx.HTML("Hello, World!
")
+// Book example.
+type Book struct {
+ Title string `json:"title"`
+}
+
+func list(ctx iris.Context) {
+ books := []Book{
+ {"Mastering Concurrency in Go"},
+ {"Go Design Patterns"},
+ {"Black Hat Go"},
+ }
+
+ ctx.JSON(books)
+ // TIP: negotiate the response between server's prioritizes
+ // and client's requirements, instead of ctx.JSON:
+ // ctx.Negotiation().JSON().MsgPack().Protobuf()
+ // ctx.Negotiate(books)
+}
+
+func create(ctx iris.Context) {
+ var b Book
+ err := ctx.ReadJSON(&b)
+ // TIP: use ctx.ReadBody(&b) to bind
+ // any type of incoming data instead.
+ if err != nil {
+ ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem().
+ Title("Book creation failure").DetailErr(err))
+ // TIP: use ctx.StopWithError(code, err) when only
+ // plain text responses are expected on errors.
+ return
+ }
+
+ println("Received Book: " + b.Title)
+
+ ctx.StatusCode(iris.StatusCreated)
}
```
+**Run** your Iris web server:
+
```sh
$ go run main.go
+> Now listening on: http://localhost:8080
+> Application started. Press CTRL+C to shut down.
+```
+
+**List** Books:
+
+```sh
+$ curl --header 'Accept-Encoding:gzip' http://localhost:8080/books
+
+[
+ {
+ "title": "Mastering Concurrency in Go"
+ },
+ {
+ "title": "Go Design Patterns"
+ },
+ {
+ "title": "Black Hat Go"
+ }
+]
+```
+
+**Create** a new Book:
+
+```sh
+$ curl -i -X POST \
+--header 'Content-Encoding:gzip' \
+--header 'Content-Type:application/json' \
+--data "{\"title\":\"Writing An Interpreter In Go\"}" \
+http://localhost:8080/books
+
+> HTTP/1.1 201 Created
+```
+
+That's how an **error** response looks like:
+
+```sh
+$ curl -X POST --data "{\"title\" \"not valid one\"}" \
+http://localhost:8080/books
+
+> HTTP/1.1 400 Bad Request
+
+{
+ "status": 400,
+ "title": "Book creation failure"
+ "detail": "invalid character '\"' after object key",
+}
```
diff --git a/_examples/compression/main.go b/_examples/compression/main.go
index 6f73a7e0..e1d989d7 100644
--- a/_examples/compression/main.go
+++ b/_examples/compression/main.go
@@ -11,7 +11,7 @@ func main() {
func newApp() *iris.Application {
app := iris.New()
// HERE and you are ready to GO:
- app.Use(iris.Compress, iris.CompressReader)
+ app.Use(iris.Compression)
app.Get("/", send)
app.Post("/", receive)
@@ -41,7 +41,7 @@ func receive(ctx iris.Context) {
/* Manually:
func enableCompression(ctx iris.Context) {
// Enable writing using compression (deflate, gzip, brotli, snappy, s2):
- err := ctx.Compress(true)
+ err := ctx.CompressWriter(true)
if err != nil {
ctx.Application().Logger().Debugf("writer: %v", err)
// if you REQUIRE server to SEND compressed data then `return` here.
diff --git a/_examples/testing/httptest/main_test.go b/_examples/testing/httptest/main_test.go
index b542ae90..9c3723bc 100644
--- a/_examples/testing/httptest/main_test.go
+++ b/_examples/testing/httptest/main_test.go
@@ -35,8 +35,10 @@ func TestHandlerUsingNetHTTP(t *testing.T) {
ctx.WriteString("Hello, World!")
}
+ // A shortcut for net/http/httptest.NewRecorder/NewRequest.
w := httptest.NewRecorder()
r := httptest.NewRequest("GET", "/", nil)
+
httptest.Do(w, r, handler)
if expected, got := "Hello, World!", w.Body.String(); expected != got {
t.Fatalf("expected body: %s but got: %s", expected, got)
diff --git a/_examples/view/herotemplate/app.go b/_examples/view/herotemplate/app.go
index 76f57812..62f7a53a 100644
--- a/_examples/view/herotemplate/app.go
+++ b/_examples/view/herotemplate/app.go
@@ -17,7 +17,7 @@ func main() {
app := iris.New()
app.Get("/users", func(ctx iris.Context) {
- ctx.Compress(true)
+ ctx.CompressWriter(true)
ctx.ContentType("text/html")
userList := []string{
diff --git a/_examples/view/overview/main.go b/_examples/view/overview/main.go
index 8222175e..8aeaabf1 100644
--- a/_examples/view/overview/main.go
+++ b/_examples/view/overview/main.go
@@ -14,7 +14,7 @@ func main() {
// - {{ current }}
app.RegisterView(iris.HTML("./templates", ".html"))
app.Get("/", func(ctx iris.Context) {
- ctx.Compress(true) // enable compression based on Accept-Encoding (e.g. "gzip").
+ ctx.CompressWriter(true) // enable compression based on Accept-Encoding (e.g. "gzip").
ctx.ViewData("Name", "iris") // the .Name inside the ./templates/hi.html.
ctx.View("hi.html") // render the template with the file name relative to the './templates'.
})
diff --git a/_examples/view/quicktemplate/controllers/execute_template.go b/_examples/view/quicktemplate/controllers/execute_template.go
index 153f6136..6baf71a4 100644
--- a/_examples/view/quicktemplate/controllers/execute_template.go
+++ b/_examples/view/quicktemplate/controllers/execute_template.go
@@ -8,7 +8,7 @@ import (
// ExecuteTemplate renders a "tmpl" partial template to the `Context.ResponseWriter`.
func ExecuteTemplate(ctx iris.Context, tmpl templates.Partial) {
- ctx.Compress(true)
+ ctx.CompressWriter(true)
ctx.ContentType("text/html")
templates.WriteTemplate(ctx, tmpl)
}
diff --git a/_examples/view/template_html_1/main.go b/_examples/view/template_html_1/main.go
index 9e8508ee..a2a3b45a 100644
--- a/_examples/view/template_html_1/main.go
+++ b/_examples/view/template_html_1/main.go
@@ -16,7 +16,7 @@ func main() {
// TIP: append .Reload(true) to reload the templates on each request.
app.Get("/", func(ctx iris.Context) {
- ctx.Compress(true)
+ ctx.CompressWriter(true)
ctx.ViewData("", mypage{"My Page title", "Hello world!"})
ctx.View("mypage.html")
// Note that: you can pass "layout" : "otherLayout.html" to bypass the config's Layout property
diff --git a/_examples/webassembly/main.go b/_examples/webassembly/main.go
index 37803c84..941839a9 100644
--- a/_examples/webassembly/main.go
+++ b/_examples/webassembly/main.go
@@ -17,7 +17,7 @@ func main() {
app.HandleDir("/", "./client")
app.Get("/", func(ctx iris.Context) {
- // ctx.Compress(true)
+ // ctx.CompressWriter(true)
ctx.ServeFile("./client/hello.html")
})
diff --git a/aliases.go b/aliases.go
index 77f85c6d..8a644f17 100644
--- a/aliases.go
+++ b/aliases.go
@@ -200,20 +200,10 @@ var (
)
var (
- // Compress is a middleware which enables writing
- // using compression, if client supports.
- Compress = func(ctx Context) {
- ctx.Compress(true)
- ctx.Next()
- }
- // CompressReader is a middleware which enables decompression,
- // when client sends compressed data.
- //
- // Similar to: func(ctx iris.Context) {
- // ctx.CompressReader(true)
- // ctx.Next()
- // }
- CompressReader = func(ctx Context) {
+ // Compression is a middleware which enables
+ // writing and reading using the best offered compression.
+ Compression = func(ctx Context) {
+ ctx.CompressWriter(true)
ctx.CompressReader(true)
ctx.Next()
}
diff --git a/context/context.go b/context/context.go
index a3270476..352a8457 100644
--- a/context/context.go
+++ b/context/context.go
@@ -2238,8 +2238,9 @@ func (ctx *Context) StreamWriter(writer func(w io.Writer) error) error {
// ClientSupportsEncoding reports whether the
// client expects one of the given "encodings" compression.
//
-// Note, instead of `Compress` method, this one just reports back the first valid encoding it sees,
+// Note, this method just reports back the first valid encoding it sees,
// meaning that request accept-encoding offers don't matter here.
+// See `CompressWriter` too.
func (ctx *Context) ClientSupportsEncoding(encodings ...string) bool {
if len(encodings) == 0 {
return false
@@ -2258,20 +2259,20 @@ func (ctx *Context) ClientSupportsEncoding(encodings ...string) bool {
return false
}
-// Compress enables or disables the compress response writer.
+// CompressWriter enables or disables the compress response writer.
// if the client expects a valid compression algorithm then this
// will change the response writer to a compress writer instead.
// All future write and rich write methods will respect this option.
// Usage:
// app.Use(func(ctx iris.Context){
-// err := ctx.Compress(true)
+// err := ctx.CompressWriter(true)
// ctx.Next()
// })
// The recommendation is to compress data as much as possible and therefore to use this field,
// but some types of resources, such as jpeg images, are already compressed.
// Sometimes, using additional compression doesn't reduce payload size and
// can even make the payload longer.
-func (ctx *Context) Compress(enable bool) error {
+func (ctx *Context) CompressWriter(enable bool) error {
cw, ok := ctx.writer.(*CompressResponseWriter)
if enable {
if ok {
@@ -2592,7 +2593,7 @@ var (
)
// WriteJSON marshals the given interface object and writes the JSON response to the 'writer'.
-// Ignores StatusCode, Compress, StreamingJSON options.
+// Ignores StatusCode and StreamingJSON options.
func WriteJSON(writer io.Writer, v interface{}, options JSON, optimize bool) (int, error) {
var (
result []byte
@@ -3176,7 +3177,7 @@ func (ctx *Context) Negotiate(v interface{}) (int, error) {
}
if encoding != "" {
- ctx.Compress(true)
+ ctx.CompressWriter(true)
}
ctx.contentTypeOnce(contentType, charset)
@@ -3679,7 +3680,8 @@ func (n *NegotiationAcceptBuilder) EncodingGzip() *NegotiationAcceptBuilder {
// ServeContent uses it to handle requests using If-Match, If-None-Match, or If-Range.
//
// Note that *os.File implements the io.ReadSeeker interface.
-// Note that compression can be registered through `ctx.Compress(true)` or `app.Use(iris.Compress)`.
+// Note that compression can be registered
+// through `ctx.CompressWriter(true)` or `app.Use(iris.Compression)`.
func (ctx *Context) ServeContent(content io.ReadSeeker, filename string, modtime time.Time) {
ctx.ServeContentWithRate(content, filename, modtime, 0, 0)
}
@@ -3730,7 +3732,8 @@ func (ctx *Context) ServeContentWithRate(content io.ReadSeeker, filename string,
//
// Use it when you want to serve assets like css and javascript files.
// If client should confirm and save the file use the `SendFile` instead.
-// Note that compression can be registered through `ctx.Compress(true)` or `app.Use(iris.Compress)`.
+// Note that compression can be registered
+// through `ctx.CompressWriter(true)` or `app.Use(iris.Compression)`.
func (ctx *Context) ServeFile(filename string) error {
return ctx.ServeFileWithRate(filename, 0, 0)
}
@@ -3769,7 +3772,8 @@ func (ctx *Context) ServeFileWithRate(filename string, limit float64, burst int)
}
// SendFile sends a file as an attachment, that is downloaded and saved locally from client.
-// Note that compression can be registered through `ctx.Compress(true)` or `app.Use(iris.Compress)`.
+// Note that compression can be registered
+// through `ctx.CompressWriter(true)` or `app.Use(iris.Compression)`.
// Use `ServeFile` if a file should be served as a page asset instead.
func (ctx *Context) SendFile(src string, destName string) error {
return ctx.SendFileWithRate(src, destName, 0, 0)
diff --git a/context/problem.go b/context/problem.go
index 27031b78..b70a427e 100644
--- a/context/problem.go
+++ b/context/problem.go
@@ -170,6 +170,15 @@ func (p Problem) Detail(detail string) Problem {
return p.Key("detail", detail)
}
+// DetailErr calls `Detail(err.Error())`.
+func (p Problem) DetailErr(err error) Problem {
+ if err == nil {
+ return p
+ }
+
+ return p.Key("detail", err.Error())
+}
+
// Instance sets the problem's instance field.
// A URI reference that identifies the specific
// occurrence of the problem. It may or may not yield further
diff --git a/core/router/fs.go b/core/router/fs.go
index e621345f..ea7033fc 100644
--- a/core/router/fs.go
+++ b/core/router/fs.go
@@ -573,7 +573,7 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
ctx.ResponseWriter().Header().Set(context.ContentDispositionHeaderKey, "attachment;filename="+destName)
}
- ctx.Compress(options.Compress)
+ ctx.CompressWriter(options.Compress)
// If limit is 0 then same as ServeContent.
ctx.ServeContentWithRate(f, info.Name(), info.ModTime(), options.Attachments.Limit, options.Attachments.Burst)
diff --git a/httptest/httptest.go b/httptest/httptest.go
index 38a2432e..379e385e 100644
--- a/httptest/httptest.go
+++ b/httptest/httptest.go
@@ -159,11 +159,12 @@ var (
func Do(w http.ResponseWriter, r *http.Request, handler iris.Handler, irisConfigurators ...iris.Configurator) {
app := new(iris.Application)
app.Configure(iris.WithConfiguration(iris.DefaultConfiguration()), iris.WithLogLevel("disable"))
+ app.Configure(irisConfigurators...)
+
app.HTTPErrorHandler = router.NewDefaultHandler(app.ConfigurationReadOnly(), app.Logger())
app.ContextPool = context.New(func() interface{} {
return context.NewContext(app)
})
- app.Configure(irisConfigurators...)
ctx := app.ContextPool.Acquire(w, r)
handler(ctx)
diff --git a/iris.go b/iris.go
index 586572c3..f98640be 100644
--- a/iris.go
+++ b/iris.go
@@ -111,8 +111,7 @@ func Default() *Application {
app := New()
app.Use(recover.New())
app.Use(requestLogger.New())
- app.Use(Compress)
- app.Use(CompressReader)
+ app.Use(Compression)
app.defaultMode = true