mirror of
https://github.com/kataras/iris.git
synced 2026-01-11 05:55:57 +00:00
reorganization of _examples and add some new examples such as iris+groupcache+mysql+docker
Former-commit-id: ed635ee95de7160cde11eaabc0c1dcb0e460a620
This commit is contained in:
39
_examples/response-writer/cache/client-side/main.go
vendored
Normal file
39
_examples/response-writer/cache/client-side/main.go
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// Package main shows how you can use the `WriteWithExpiration`
|
||||
// based on the "modtime", if it's newer than the request header then
|
||||
// it will refresh the contents, otherwise will let the client (99.9% the browser)
|
||||
// to handle the cache mechanism, it's faster than iris.Cache because server-side
|
||||
// has nothing to do and no need to store the responses in the memory.
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
const refreshEvery = 10 * time.Second
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.Use(iris.Cache304(refreshEvery))
|
||||
// same as:
|
||||
// app.Use(func(ctx iris.Context) {
|
||||
// now := time.Now()
|
||||
// if modified, err := ctx.CheckIfModifiedSince(now.Add(-refresh)); !modified && err == nil {
|
||||
// ctx.WriteNotModified()
|
||||
// return
|
||||
// }
|
||||
|
||||
// ctx.SetLastModified(now)
|
||||
|
||||
// ctx.Next()
|
||||
// })
|
||||
|
||||
app.Get("/", greet)
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
func greet(ctx iris.Context) {
|
||||
ctx.Header("X-Custom", "my custom header")
|
||||
ctx.Writef("Hello World! %s", time.Now())
|
||||
}
|
||||
80
_examples/response-writer/cache/simple/main.go
vendored
Normal file
80
_examples/response-writer/cache/simple/main.go
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
|
||||
"github.com/kataras/iris/v12/cache"
|
||||
)
|
||||
|
||||
var markdownContents = []byte(`## Hello Markdown
|
||||
|
||||
This is a sample of Markdown contents
|
||||
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
All features of Sundown are supported, including:
|
||||
|
||||
* **Compatibility**. The Markdown v1.0.3 test suite passes with
|
||||
the --tidy option. Without --tidy, the differences are
|
||||
mostly in whitespace and entity escaping, where blackfriday is
|
||||
more consistent and cleaner.
|
||||
|
||||
* **Common extensions**, including table support, fenced code
|
||||
blocks, autolinks, strikethroughs, non-strict emphasis, etc.
|
||||
|
||||
* **Safety**. Blackfriday is paranoid when parsing, making it safe
|
||||
to feed untrusted user input without fear of bad things
|
||||
happening. The test suite stress tests this and there are no
|
||||
known inputs that make it crash. If you find one, please let me
|
||||
know and send me the input that does it.
|
||||
|
||||
NOTE: "safety" in this context means *runtime safety only*. In order to
|
||||
protect yourself against JavaScript injection in untrusted content, see
|
||||
[this example](https://github.com/russross/blackfriday#sanitize-untrusted-content).
|
||||
|
||||
* **Fast processing**. It is fast enough to render on-demand in
|
||||
most web applications without having to cache the output.
|
||||
|
||||
* **Routine safety**. You can run multiple parsers in different
|
||||
goroutines without ill effect. There is no dependence on global
|
||||
shared state.
|
||||
|
||||
* **Minimal dependencies**. Blackfriday only depends on standard
|
||||
library packages in Go. The source code is pretty
|
||||
self-contained, so it is easy to add to any project, including
|
||||
Google App Engine projects.
|
||||
|
||||
* **Standards compliant**. Output successfully validates using the
|
||||
W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional.
|
||||
|
||||
[this is a link](https://github.com/kataras/iris) `)
|
||||
|
||||
// Cache should not be used on handlers that contain dynamic data.
|
||||
// Cache is a good and a must-feature on static content, i.e "about page" or for a whole blog site.
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.Logger().SetLevel("debug")
|
||||
app.Get("/", cache.Handler(10*time.Second), writeMarkdown)
|
||||
// saves its content on the first request and serves it instead of re-calculating the content.
|
||||
// After 10 seconds it will be cleared and reset.
|
||||
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
func writeMarkdown(ctx iris.Context) {
|
||||
// tap multiple times the browser's refresh button and you will
|
||||
// see this println only once every 10 seconds.
|
||||
println("Handler executed. Content refreshed.")
|
||||
|
||||
ctx.Markdown(markdownContents)
|
||||
}
|
||||
|
||||
/* Note that `HandleDir` does use the browser's disk caching by-default
|
||||
therefore, register the cache handler AFTER any HandleDir calls,
|
||||
for a faster solution that server doesn't need to keep track of the response
|
||||
navigate to https://github.com/kataras/iris/blob/master/_examples/cache/client-side/main.go */
|
||||
114
_examples/response-writer/content-negotiation/main.go
Normal file
114
_examples/response-writer/content-negotiation/main.go
Normal file
@@ -0,0 +1,114 @@
|
||||
// Package main contains three different ways to render content based on the client's accepted.
|
||||
package main
|
||||
|
||||
import "github.com/kataras/iris/v12"
|
||||
|
||||
type testdata struct {
|
||||
Name string `json:"name" xml:"Name"`
|
||||
Age int `json:"age" xml:"Age"`
|
||||
}
|
||||
|
||||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
app.Logger().SetLevel("debug")
|
||||
|
||||
// app.Use(func(ctx iris.Context) {
|
||||
// requestedMime := ctx.URLParamDefault("type", "application/json")
|
||||
//
|
||||
// ctx.Negotiation().Accept.Override().MIME(requestedMime, nil)
|
||||
// ctx.Next()
|
||||
// })
|
||||
|
||||
app.Get("/resource", func(ctx iris.Context) {
|
||||
data := testdata{
|
||||
Name: "test name",
|
||||
Age: 26,
|
||||
}
|
||||
|
||||
// Server allows response only JSON and XML. These values
|
||||
// are compared with the clients mime needs. Iris comes with default mime types responses
|
||||
// but you can add a custom one by the `Negotiation().Mime(mime, content)` method,
|
||||
// same for the "accept".
|
||||
// You can also pass a custom ContentSelector(mime string) or ContentNegotiator to the
|
||||
// `Context.Negotiate` method if you want to perform more advanced things.
|
||||
//
|
||||
//
|
||||
// By-default the client accept mime is retrieved by the "Accept" header
|
||||
// Indeed you can override or update it by `Negotiation().Accept.XXX` i.e
|
||||
// ctx.Negotiation().Accept.Override().XML()
|
||||
//
|
||||
// All these values can change inside middlewares, the `Negotiation().Override()` and `.Accept.Override()`
|
||||
// can override any previously set values.
|
||||
// Order matters, if the client accepts anything (*/*)
|
||||
// then the first prioritized mime's response data will be rendered.
|
||||
ctx.Negotiation().JSON().XML()
|
||||
// Accept-Charset vs:
|
||||
ctx.Negotiation().Charset("utf-8", "iso-8859-7")
|
||||
// Alternatively you can define the content/data per mime type
|
||||
// anywhere in the handlers chain using the optional "v" variadic
|
||||
// input argument of the Context.Negotiation().JSON,XML,YAML,Binary,Text,HTML(...) and e.t.c
|
||||
// example (order matters):
|
||||
// ctx.Negotiation().JSON(data).XML(data).Any("content for */*")
|
||||
// ctx.Negotiate(nil)
|
||||
|
||||
// if not nil passed in the `Context.Negotiate` method
|
||||
// then it overrides any contents made by the negotitation builder above.
|
||||
_, err := ctx.Negotiate(data)
|
||||
if err != nil {
|
||||
ctx.Writef("%v", err)
|
||||
}
|
||||
})
|
||||
|
||||
app.Get("/resource2", func(ctx iris.Context) {
|
||||
jsonAndXML := testdata{
|
||||
Name: "test name",
|
||||
Age: 26,
|
||||
}
|
||||
|
||||
// I prefer that one, as it gives me the freedom to modify
|
||||
// response data per accepted mime content type on middlewares as well.
|
||||
ctx.Negotiation().
|
||||
JSON(jsonAndXML).
|
||||
XML(jsonAndXML).
|
||||
HTML("<h1>Test Name</h1><h2>Age 26</h2>")
|
||||
|
||||
ctx.Negotiate(nil)
|
||||
})
|
||||
|
||||
app.Get("/resource3", func(ctx iris.Context) {
|
||||
// If that line is missing and the requested
|
||||
// mime type of content is */* or application/xml or application/json
|
||||
// then 406 Not Acceptable http error code will be rendered instead.
|
||||
//
|
||||
// We also add the "gzip" algorithm as an option to encode
|
||||
// resources on send.
|
||||
ctx.Negotiation().JSON().XML().HTML().EncodingGzip()
|
||||
|
||||
jsonAndXML := testdata{
|
||||
Name: "test name",
|
||||
Age: 26,
|
||||
}
|
||||
|
||||
// Prefer that way instead of the '/resource2' above
|
||||
// if "iris.N" is a static one and can be declared
|
||||
// outside of a handler.
|
||||
ctx.Negotiate(iris.N{
|
||||
// Text: for text/plain,
|
||||
// Markdown: for text/mardown,
|
||||
// Binary: for application/octet-stream,
|
||||
// YAML: for application/x-yaml,
|
||||
// JSONP: for text/javascript
|
||||
// Other: for anything else,
|
||||
JSON: jsonAndXML, // for application/json
|
||||
XML: jsonAndXML, // for application/xml or text/xml
|
||||
HTML: "<h1>Test Name</h1><h2>Age 26</h2>", // for text/html
|
||||
})
|
||||
})
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := newApp()
|
||||
app.Listen(":8080")
|
||||
}
|
||||
80
_examples/response-writer/content-negotiation/main_test.go
Normal file
80
_examples/response-writer/content-negotiation/main_test.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/httptest"
|
||||
)
|
||||
|
||||
func TestContentNegotiation(t *testing.T) {
|
||||
var (
|
||||
expectedJSONResponse = testdata{
|
||||
Name: "test name",
|
||||
Age: 26,
|
||||
}
|
||||
expectedXMLResponse, _ = xml.Marshal(expectedJSONResponse)
|
||||
expectedHTMLResponse = "<h1>Test Name</h1><h2>Age 26</h2>"
|
||||
)
|
||||
|
||||
app := newApp()
|
||||
app.Configure(iris.WithOptimizations)
|
||||
e := httptest.New(t, app)
|
||||
|
||||
e.GET("/resource").WithHeader("Accept", "application/json").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("application/json", "utf-8").
|
||||
JSON().Equal(expectedJSONResponse)
|
||||
e.GET("/resource").WithHeader("Accept", "application/xml").WithHeader("Accept-Charset", "iso-8859-7").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("application/xml", "iso-8859-7").
|
||||
Body().Equal(string(expectedXMLResponse))
|
||||
|
||||
e.GET("/resource2").WithHeader("Accept", "application/json").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("application/json", "utf-8").
|
||||
JSON().Equal(expectedJSONResponse)
|
||||
e.GET("/resource2").WithHeader("Accept", "application/xml").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("application/xml", "utf-8").
|
||||
Body().Equal(string(expectedXMLResponse))
|
||||
e.GET("/resource2").WithHeader("Accept", "text/html").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("text/html", "utf-8").
|
||||
Body().Equal(expectedHTMLResponse)
|
||||
|
||||
e.GET("/resource3").WithHeader("Accept", "application/json").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("application/json", "utf-8").
|
||||
JSON().Equal(expectedJSONResponse)
|
||||
e.GET("/resource3").WithHeader("Accept", "application/xml").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("application/xml", "utf-8").
|
||||
Body().Equal(string(expectedXMLResponse))
|
||||
|
||||
// test html with "gzip" encoding algorithm.
|
||||
rawGzipResponse := e.GET("/resource3").WithHeader("Accept", "text/html").
|
||||
WithHeader("Accept-Encoding", "gzip").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("text/html", "utf-8").
|
||||
ContentEncoding("gzip").
|
||||
Body().Raw()
|
||||
|
||||
zr, err := gzip.NewReader(bytes.NewReader([]byte(rawGzipResponse)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rawResponse, err := ioutil.ReadAll(zr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected, got := expectedHTMLResponse, string(rawResponse); expected != got {
|
||||
t.Fatalf("expected response to be:\n%s but got:\n%s", expected, got)
|
||||
}
|
||||
}
|
||||
50
_examples/response-writer/sse-third-party/main.go
vendored
Normal file
50
_examples/response-writer/sse-third-party/main.go
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/r3labs/sse"
|
||||
)
|
||||
|
||||
// First of all install the sse third-party package (you can use other if you don't like this approach or go ahead to the "sse" example)
|
||||
// $ go get -u github.com/r3labs/sse
|
||||
func main() {
|
||||
app := iris.New()
|
||||
s := sse.New()
|
||||
/*
|
||||
This creates a new stream inside of the scheduler.
|
||||
Seeing as there are no consumers, publishing a message
|
||||
to this channel will do nothing.
|
||||
Clients can connect to this stream once the iris handler is started
|
||||
by specifying stream as a url parameter, like so:
|
||||
http://localhost:8080/events?stream=messages
|
||||
*/
|
||||
s.CreateStream("messages")
|
||||
|
||||
app.Any("/events", iris.FromStd(s.HTTPHandler))
|
||||
|
||||
go func() {
|
||||
// You design when to send messages to the client,
|
||||
// here we just wait 5 seconds to send the first message
|
||||
// in order to give u time to open a browser window...
|
||||
time.Sleep(5 * time.Second)
|
||||
// Publish a payload to the stream.
|
||||
s.Publish("messages", &sse.Event{
|
||||
Data: []byte("ping"),
|
||||
})
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
s.Publish("messages", &sse.Event{
|
||||
Data: []byte("second message"),
|
||||
})
|
||||
time.Sleep(2 * time.Second)
|
||||
s.Publish("messages", &sse.Event{
|
||||
Data: []byte("third message"),
|
||||
})
|
||||
}() // ...
|
||||
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
/* For a golang SSE client you can look at: https://github.com/r3labs/sse#example-client */
|
||||
192
_examples/response-writer/sse/main.go
Normal file
192
_examples/response-writer/sse/main.go
Normal file
@@ -0,0 +1,192 @@
|
||||
// Package main shows how to send continuous event messages to the clients through SSE via a broker.
|
||||
// Read details at: https://www.w3schools.com/htmL/html5_serversentevents.asp and
|
||||
// https://robots.thoughtbot.com/writing-a-server-sent-events-server-in-go
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/golog"
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
// A Broker holds open client connections,
|
||||
// listens for incoming events on its Notifier channel
|
||||
// and broadcast event data to all registered connections.
|
||||
type Broker struct {
|
||||
|
||||
// Events are pushed to this channel by the main events-gathering routine.
|
||||
Notifier chan []byte
|
||||
|
||||
// New client connections.
|
||||
newClients chan chan []byte
|
||||
|
||||
// Closed client connections.
|
||||
closingClients chan chan []byte
|
||||
|
||||
// Client connections registry.
|
||||
clients map[chan []byte]bool
|
||||
}
|
||||
|
||||
// NewBroker returns a new broker factory.
|
||||
func NewBroker() *Broker {
|
||||
b := &Broker{
|
||||
Notifier: make(chan []byte, 1),
|
||||
newClients: make(chan chan []byte),
|
||||
closingClients: make(chan chan []byte),
|
||||
clients: make(map[chan []byte]bool),
|
||||
}
|
||||
|
||||
// Set it running - listening and broadcasting events.
|
||||
go b.listen()
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Listen on different channels and act accordingly.
|
||||
func (b *Broker) listen() {
|
||||
for {
|
||||
select {
|
||||
case s := <-b.newClients:
|
||||
// A new client has connected.
|
||||
// Register their message channel.
|
||||
b.clients[s] = true
|
||||
golog.Infof("Client added. %d registered clients", len(b.clients))
|
||||
|
||||
case s := <-b.closingClients:
|
||||
// A client has dettached and we want to
|
||||
// stop sending them messages.
|
||||
delete(b.clients, s)
|
||||
golog.Infof("Removed client. %d registered clients", len(b.clients))
|
||||
|
||||
case event := <-b.Notifier:
|
||||
// We got a new event from the outside!
|
||||
// Send event to all connected clients.
|
||||
for clientMessageChan := range b.clients {
|
||||
clientMessageChan <- event
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Broker) ServeHTTP(ctx iris.Context) {
|
||||
// Make sure that the writer supports flushing.
|
||||
|
||||
flusher, ok := ctx.ResponseWriter().Flusher()
|
||||
if !ok {
|
||||
ctx.StatusCode(iris.StatusHTTPVersionNotSupported)
|
||||
ctx.WriteString("Streaming unsupported!")
|
||||
return
|
||||
}
|
||||
|
||||
// Set the headers related to event streaming, you can omit the "application/json" if you send plain text.
|
||||
// If you develop a go client, you must have: "Accept" : "application/json, text/event-stream" header as well.
|
||||
ctx.ContentType("application/json, text/event-stream")
|
||||
ctx.Header("Cache-Control", "no-cache")
|
||||
ctx.Header("Connection", "keep-alive")
|
||||
// We also add a Cross-origin Resource Sharing header so browsers on different domains can still connect.
|
||||
ctx.Header("Access-Control-Allow-Origin", "*")
|
||||
|
||||
// Each connection registers its own message channel with the Broker's connections registry.
|
||||
messageChan := make(chan []byte)
|
||||
|
||||
// Signal the broker that we have a new connection.
|
||||
b.newClients <- messageChan
|
||||
|
||||
// Listen to connection close and when the entire request handler chain exits(this handler here) and un-register messageChan.
|
||||
ctx.OnClose(func() {
|
||||
// Remove this client from the map of connected clients
|
||||
// when this handler exits.
|
||||
b.closingClients <- messageChan
|
||||
})
|
||||
|
||||
// Block waiting for messages broadcast on this connection's messageChan.
|
||||
for {
|
||||
// Write to the ResponseWriter.
|
||||
// Server Sent Events compatible.
|
||||
ctx.Writef("data: %s\n\n", <-messageChan)
|
||||
// or json: data:{obj}.
|
||||
|
||||
// Flush the data immediately instead of buffering it for later.
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
type event struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
const script = `<script type="text/javascript">
|
||||
if(typeof(EventSource) !== "undefined") {
|
||||
console.log("server-sent events supported");
|
||||
var client = new EventSource("http://localhost:8080/events");
|
||||
var index = 1;
|
||||
client.onmessage = function (evt) {
|
||||
console.log(evt);
|
||||
// it's not required that you send and receive JSON, you can just output the "evt.data" as well.
|
||||
dataJSON = JSON.parse(evt.data)
|
||||
var table = document.getElementById("messagesTable");
|
||||
var row = table.insertRow(index);
|
||||
var cellTimestamp = row.insertCell(0);
|
||||
var cellMessage = row.insertCell(1);
|
||||
cellTimestamp.innerHTML = dataJSON.timestamp;
|
||||
cellMessage.innerHTML = dataJSON.message;
|
||||
index++;
|
||||
|
||||
window.scrollTo(0,document.body.scrollHeight);
|
||||
};
|
||||
} else {
|
||||
document.getElementById("header").innerHTML = "<h2>SSE not supported by this client-protocol</h2>";
|
||||
}
|
||||
</script>`
|
||||
|
||||
func main() {
|
||||
broker := NewBroker()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
now := time.Now()
|
||||
evt := event{
|
||||
Timestamp: now.Unix(),
|
||||
Message: fmt.Sprintf("Hello at %s", now.Format(time.RFC1123)),
|
||||
}
|
||||
|
||||
evtBytes, err := json.Marshal(evt)
|
||||
if err != nil {
|
||||
golog.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
broker.Notifier <- evtBytes
|
||||
}
|
||||
}()
|
||||
|
||||
app := iris.New()
|
||||
app.Logger().SetLevel("debug")
|
||||
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.HTML(
|
||||
`<html><head><title>SSE</title>` + script + `</head>
|
||||
<body>
|
||||
<h1 id="header">Waiting for messages...</h1>
|
||||
<table id="messagesTable" border="1">
|
||||
<tr>
|
||||
<th>Timestamp (server)</th>
|
||||
<th>Message</th>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>`)
|
||||
})
|
||||
|
||||
app.Get("/events", broker.ServeHTTP)
|
||||
|
||||
// http://localhost:8080
|
||||
// http://localhost:8080/events
|
||||
app.Listen(":8080")
|
||||
}
|
||||
17
_examples/response-writer/sse/optional.sse.mini.js.html
Normal file
17
_examples/response-writer/sse/optional.sse.mini.js.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!-- you can just put that to your favourite browser -->
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>SSE (javascript side)</title>
|
||||
|
||||
<script type="text/javascript">
|
||||
var client = new EventSource("http://localhost:8080/events")
|
||||
client.onmessage = function (evt) {
|
||||
console.log(evt)
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Open the browser's console(F12) and watch for incoming event messages</h1>
|
||||
</body>
|
||||
</html>
|
||||
54
_examples/response-writer/stream-writer/main.go
Normal file
54
_examples/response-writer/stream-writer/main.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt" // just an optional helper
|
||||
"io"
|
||||
"time" // showcase the delay
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.ContentType("text/html")
|
||||
ctx.Header("Transfer-Encoding", "chunked")
|
||||
i := 0
|
||||
ints := []int{1, 2, 3, 5, 7, 9, 11, 13, 15, 17, 23, 29}
|
||||
// Send the response in chunks and wait for half a second between each chunk.
|
||||
ctx.StreamWriter(func(w io.Writer) bool {
|
||||
fmt.Fprintf(w, "Message number %d<br>", ints[i])
|
||||
time.Sleep(500 * time.Millisecond) // simulate delay.
|
||||
if i == len(ints)-1 {
|
||||
return false // close and flush
|
||||
}
|
||||
i++
|
||||
return true // continue write
|
||||
})
|
||||
})
|
||||
|
||||
type messageNumber struct {
|
||||
Number int `json:"number"`
|
||||
}
|
||||
|
||||
app.Get("/alternative", func(ctx iris.Context) {
|
||||
ctx.ContentType("application/json")
|
||||
ctx.Header("Transfer-Encoding", "chunked")
|
||||
i := 0
|
||||
ints := []int{1, 2, 3, 5, 7, 9, 11, 13, 15, 17, 23, 29}
|
||||
// Send the response in chunks and wait for half a second between each chunk.
|
||||
for {
|
||||
ctx.JSON(messageNumber{Number: ints[i]})
|
||||
ctx.WriteString("\n")
|
||||
time.Sleep(500 * time.Millisecond) // simulate delay.
|
||||
if i == len(ints)-1 {
|
||||
break
|
||||
}
|
||||
i++
|
||||
ctx.ResponseWriter().Flush()
|
||||
}
|
||||
})
|
||||
|
||||
app.Listen(":8080")
|
||||
}
|
||||
54
_examples/response-writer/transactions/main.go
Normal file
54
_examples/response-writer/transactions/main.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/context"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
|
||||
// subdomains works with all available routers, like other features too.
|
||||
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.BeginTransaction(func(t *context.Transaction) {
|
||||
// OPTIONAl STEP: , if true then the next transictions will not be executed if this transiction fails
|
||||
// t.SetScope(context.RequestTransactionScope)
|
||||
|
||||
// OPTIONAL STEP:
|
||||
// create a new custom type of error here to keep track of the status code and reason message
|
||||
err := context.NewTransactionErrResult()
|
||||
|
||||
// we should use t.Context if we want to rollback on any errors lives inside this function clojure.
|
||||
t.Context().Text("Blablabla this should not be sent to the client because we will fill the err with a message and status")
|
||||
|
||||
// virtualize a fake error here, for the sake of the example
|
||||
fail := true
|
||||
if fail {
|
||||
err.StatusCode = iris.StatusInternalServerError
|
||||
// NOTE: if empty reason then the default or the custom http error will be fired (like ctx.FireStatusCode)
|
||||
err.Reason = "Error: Virtual failure!!"
|
||||
}
|
||||
|
||||
// OPTIONAl STEP:
|
||||
// but useful if we want to post back an error message to the client if the transaction failed.
|
||||
// if the reason is empty then the transaction completed successfully,
|
||||
// otherwise we rollback the whole response writer's body,
|
||||
// headers and cookies, status code and everything lives inside this transaction
|
||||
t.Complete(err)
|
||||
})
|
||||
|
||||
ctx.BeginTransaction(func(t *context.Transaction) {
|
||||
t.Context().HTML("<h1>This will sent at all cases because it lives on different transaction and it doesn't fails</h1>")
|
||||
// * if we don't have any 'throw error' logic then no need of scope.Complete()
|
||||
})
|
||||
|
||||
// OPTIONALLY, depends on the usage:
|
||||
// at any case, what ever happens inside the context's transactions send this to the client
|
||||
ctx.HTML("<h1>Let's add a second html message to the response, " +
|
||||
"if the transaction was failed and it was request scoped then this message would " +
|
||||
"not been shown. But it has a transient scope(default) so, it is visible as expected!</h1>")
|
||||
})
|
||||
|
||||
app.Listen(":8080")
|
||||
}
|
||||
24
_examples/response-writer/write-gzip/main.go
Normal file
24
_examples/response-writer/write-gzip/main.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import "github.com/kataras/iris/v12"
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
// app.Use(iris.Gzip)
|
||||
// func(ctx iris.Context) { ctx.Gzip(true/false)}
|
||||
// OR:
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.WriteGzip([]byte("Hello World!"))
|
||||
ctx.Header("X-Custom",
|
||||
"Headers can be set here after WriteGzip as well, because the data are kept before sent to the client when using the context's GzipResponseWriter and ResponseRecorder.")
|
||||
})
|
||||
|
||||
app.Get("/2", func(ctx iris.Context) {
|
||||
// same as the `WriteGzip`.
|
||||
// However GzipResponseWriter gives you more options, like
|
||||
// reset data, disable and more, look its methods.
|
||||
ctx.GzipResponseWriter().WriteString("Hello World!")
|
||||
})
|
||||
|
||||
app.Listen(":8080")
|
||||
}
|
||||
117
_examples/response-writer/write-rest/main.go
Normal file
117
_examples/response-writer/write-rest/main.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/context"
|
||||
)
|
||||
|
||||
// User example struct for json and msgpack.
|
||||
type User struct {
|
||||
Firstname string `json:"firstname" msgpack:"firstname"`
|
||||
Lastname string `json:"lastname" msgpack:"lastname"`
|
||||
City string `json:"city" msgpack:"city"`
|
||||
Age int `json:"age" msgpack:"age"`
|
||||
}
|
||||
|
||||
// ExampleXML just a test struct to view represents xml content-type
|
||||
type ExampleXML struct {
|
||||
XMLName xml.Name `xml:"example"`
|
||||
One string `xml:"one,attr"`
|
||||
Two string `xml:"two,attr"`
|
||||
}
|
||||
|
||||
// ExampleYAML just a test struct to write yaml to the client.
|
||||
type ExampleYAML struct {
|
||||
Name string `yaml:"name"`
|
||||
ServerAddr string `yaml:"ServerAddr"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
|
||||
// Read
|
||||
app.Post("/decode", func(ctx iris.Context) {
|
||||
// Read https://github.com/kataras/iris/blob/master/_examples/request-body/read-json/main.go as well.
|
||||
var user User
|
||||
ctx.ReadJSON(&user)
|
||||
|
||||
ctx.Writef("%s %s is %d years old and comes from %s!", user.Firstname, user.Lastname, user.Age, user.City)
|
||||
})
|
||||
|
||||
// Write
|
||||
app.Get("/encode", func(ctx iris.Context) {
|
||||
u := User{
|
||||
Firstname: "John",
|
||||
Lastname: "Doe",
|
||||
City: "Neither FBI knows!!!",
|
||||
Age: 25,
|
||||
}
|
||||
|
||||
// Manually setting a content type: ctx.ContentType("text/javascript")
|
||||
ctx.JSON(u)
|
||||
})
|
||||
|
||||
// Other content types,
|
||||
|
||||
app.Get("/binary", func(ctx iris.Context) {
|
||||
// useful when you want force-download of contents of raw bytes form.
|
||||
ctx.Binary([]byte("Some binary data here."))
|
||||
})
|
||||
|
||||
app.Get("/text", func(ctx iris.Context) {
|
||||
ctx.Text("Plain text here")
|
||||
})
|
||||
|
||||
app.Get("/json", func(ctx iris.Context) {
|
||||
ctx.JSON(map[string]string{"hello": "json"}) // or myjsonStruct{hello:"json}
|
||||
})
|
||||
|
||||
app.Get("/jsonp", func(ctx iris.Context) {
|
||||
ctx.JSONP(map[string]string{"hello": "jsonp"}, context.JSONP{Callback: "callbackName"})
|
||||
})
|
||||
|
||||
app.Get("/xml", func(ctx iris.Context) {
|
||||
ctx.XML(ExampleXML{One: "hello", Two: "xml"}) // or iris.Map{"One":"hello"...}
|
||||
})
|
||||
|
||||
app.Get("/markdown", func(ctx iris.Context) {
|
||||
ctx.Markdown([]byte("# Hello Dynamic Markdown -- iris"))
|
||||
})
|
||||
|
||||
app.Get("/yaml", func(ctx iris.Context) {
|
||||
ctx.YAML(ExampleYAML{Name: "Iris", ServerAddr: "localhost:8080"})
|
||||
})
|
||||
|
||||
app.Get("/msgpack", func(ctx iris.Context) {
|
||||
u := User{
|
||||
Firstname: "John",
|
||||
Lastname: "Doe",
|
||||
City: "Neither FBI knows!!!",
|
||||
Age: 25,
|
||||
}
|
||||
|
||||
ctx.MsgPack(u)
|
||||
})
|
||||
|
||||
// http://localhost:8080/decode
|
||||
// http://localhost:8080/encode
|
||||
//
|
||||
// http://localhost:8080/binary
|
||||
// http://localhost:8080/text
|
||||
// http://localhost:8080/json
|
||||
// http://localhost:8080/jsonp
|
||||
// http://localhost:8080/xml
|
||||
// http://localhost:8080/markdown
|
||||
// http://localhost:8080/msgpack
|
||||
//
|
||||
// `iris.WithOptimizations` is an optional configurator,
|
||||
// if passed to the `Run` then it will ensure that the application
|
||||
// response to the client as fast as possible.
|
||||
//
|
||||
//
|
||||
// `iris.WithoutServerError` is an optional configurator,
|
||||
// if passed to the `Run` then it will not print its passed error as an actual server error.
|
||||
app.Listen(":8080", iris.WithOptimizations)
|
||||
}
|
||||
Reference in New Issue
Block a user