mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
simplify readme
Former-commit-id: 95158c51fc01195b60f9ee873ab416c314568198
This commit is contained in:
parent
8b5c106d1c
commit
1ec8452208
248
README.md
248
README.md
|
@ -211,128 +211,15 @@ id: 1234; page: 1; name: manu; message: this_is_great
|
|||
|
||||
### Upload files
|
||||
|
||||
#### Single file
|
||||
|
||||
Detail [example code](_examples/http_request/upload-file/main.go).
|
||||
- [single file upload](_examples/http_request/upload-file/main.go)
|
||||
- [multi file upload](_examples/http_request/upload-files)
|
||||
|
||||
```go
|
||||
const maxSize = 5 << 20 // 5MB
|
||||
|
||||
func main() {
|
||||
app.Post("/upload", func(ctx iris.Context) {
|
||||
// Get the file from the request.
|
||||
file, info, err := ctx.FormFile("file")
|
||||
if err != nil {
|
||||
ctx.StatusCode(iris.StatusInternalServerError)
|
||||
ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
fname := info.Filename
|
||||
|
||||
// Create a file with the same name
|
||||
// assuming that you have a folder named 'uploads'
|
||||
out, err := os.OpenFile("./uploads/"+fname,
|
||||
os.O_WRONLY|os.O_CREATE, 0666)
|
||||
|
||||
if err != nil {
|
||||
ctx.StatusCode(iris.StatusInternalServerError)
|
||||
ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
|
||||
return
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
io.Copy(out, file)
|
||||
})
|
||||
|
||||
// start the server at http://localhost:8080 with post limit at 5 MB
|
||||
// (defaults to 32MB, read below).
|
||||
app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(maxSize))
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/upload \
|
||||
-F "file=@./myfile.zip" \
|
||||
-H "Content-Type: multipart/form-data"
|
||||
```
|
||||
|
||||
* The default post max size is 32MB,
|
||||
you can extend it to read more data using the `iris.WithPostMaxMemory(maxSize)` configurator at `app.Run`,
|
||||
note that this will not be enough for your needs, read below.
|
||||
|
||||
* The faster way to check the size is using the `ctx.GetContentLength()` which returns the whole request's size
|
||||
(plus a logical number like 2MB or even 10MB for the rest of the size like headers). You can create a
|
||||
middleware to adapt this to any necessary handler.
|
||||
|
||||
```go
|
||||
myLimiter := func(ctx iris.Context) {
|
||||
if ctx.GetContentLength() > maxSize { // + 2 << 20 {
|
||||
ctx.StatusCode(iris.StatusRequestEntityTooLarge)
|
||||
return
|
||||
}
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
app.Post("/upload", myLimiter, myUploadHandler)
|
||||
```
|
||||
|
||||
* Most clients will set the "Content-Length" header (like browsers) but it's always better to make sure that any client
|
||||
can't send data that your server can't or doesn't want to handle. This can be happen using
|
||||
the `app.Use(LimitRequestBodySize(maxSize))` (as app or route middleware)
|
||||
or the `ctx.SetMaxRequestBodySize(maxSize)` to limit the request based on a customized logic inside a particular handler, they're the same,
|
||||
read below.
|
||||
|
||||
* You can force-limit the request body size inside a handler using the `ctx.SetMaxRequestBodySize(maxSize)`,
|
||||
this will force the connection to close if the incoming data are larger (most clients will receive it as "connection reset"),
|
||||
use that to make sure that the client will not send data that your server can't or doesn't want to accept, as a fallback.
|
||||
|
||||
```go
|
||||
app.Post("/upload", iris.LimitRequestBodySize(maxSize), myUploadHandler)
|
||||
```
|
||||
|
||||
OR
|
||||
|
||||
```go
|
||||
app.Post("/upload", func(ctx iris.Context){
|
||||
ctx.SetMaxRequestBodySize(maxSize)
|
||||
|
||||
// [...]
|
||||
})
|
||||
```
|
||||
|
||||
* Another way is to receive the data and check the second return value's `Size` value of the `ctx.FormFile`, i.e `info.Size`, this will give you
|
||||
the exact file size, not the whole incoming request data length.
|
||||
|
||||
```go
|
||||
app.Post("/upload", func(ctx iris.Context){
|
||||
file, info, err := ctx.FormFile("file")
|
||||
if err != nil {
|
||||
ctx.StatusCode(iris.StatusInternalServerError)
|
||||
ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
if info.Size > maxSize {
|
||||
ctx.StatusCode(iris.StatusRequestEntityTooLarge)
|
||||
return
|
||||
}
|
||||
|
||||
// [...]
|
||||
})
|
||||
```
|
||||
|
||||
#### Multiple files (easy way)
|
||||
|
||||
See the detail [example code](_examples/http_request/upload-files).
|
||||
|
||||
```go
|
||||
func main() {
|
||||
app := iris.Default()
|
||||
app.Post("/upload", func(ctx iris.Context) {
|
||||
app.Post("/upload", iris.LimitRequestBodySize(maxSize), func(ctx iris.Context) {
|
||||
//
|
||||
// UploadFormFiles
|
||||
// uploads any number of incoming files ("multiple" property on the form input).
|
||||
|
@ -365,56 +252,6 @@ func beforeSave(ctx iris.Context, file *multipart.FileHeader) {
|
|||
}
|
||||
```
|
||||
|
||||
#### Multiple files (manual way)
|
||||
|
||||
```go
|
||||
app.Post("/upload_manual", func(ctx iris.Context) {
|
||||
r := ctx.Request()
|
||||
// Get the max post value size passed via iris.WithPostMaxMemory.
|
||||
maxSize := ctx.Application().ConfigurationReadOnly().GetPostMaxMemory()
|
||||
|
||||
err := r.ParseMultipartForm(maxSize)
|
||||
if err != nil {
|
||||
ctx.StatusCode(iris.StatusInternalServerError)
|
||||
ctx.WriteString(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
form := r.MultipartForm
|
||||
|
||||
files := form.File["files[]"]
|
||||
failures := 0
|
||||
for _, file := range files {
|
||||
_, err = saveUploadedFile(file, "./uploads")
|
||||
if err != nil {
|
||||
failures++
|
||||
ctx.Writef("failed to upload: %s\n", file.Filename)
|
||||
}
|
||||
}
|
||||
ctx.Writef("%d files uploaded", len(files)-failures)
|
||||
})
|
||||
```
|
||||
|
||||
```go
|
||||
func saveUploadedFile(fh *multipart.FileHeader, destDirectory string) (int64, error) {
|
||||
src, err := fh.Open()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
out, err := os.OpenFile(filepath.Join(destDirectory, fh.Filename),
|
||||
os.O_WRONLY|os.O_CREATE, os.FileMode(0666))
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
return io.Copy(out, src)
|
||||
}
|
||||
```
|
||||
|
||||
How to `curl`:
|
||||
|
||||
```bash
|
||||
|
@ -585,6 +422,8 @@ func main() {
|
|||
|
||||
Iris uses [**go-playground/validator.v9**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](http://godoc.org/gopkg.in/go-playground/validator.v9#hdr-Baked_In_Validators_and_Tags).
|
||||
|
||||
Example [detail code](_examples/http_request/read-json-struct-validation/main.go).
|
||||
|
||||
Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set `json:"fieldname"`.
|
||||
|
||||
```go
|
||||
|
@ -660,79 +499,48 @@ func main() {
|
|||
fmt.Println(err.Value())
|
||||
fmt.Println(err.Param())
|
||||
fmt.Println()
|
||||
|
||||
// Or collect these as json objects
|
||||
// and send back to the client the collected errors via ctx.JSON
|
||||
// {
|
||||
// "namespace": err.Namespace(),
|
||||
// "field": err.Field(),
|
||||
// "struct_namespace": err.StructNamespace(),
|
||||
// "struct_field": err.StructField(),
|
||||
// "tag": err.Tag(),
|
||||
// "actual_tag": err.ActualTag(),
|
||||
// "kind": err.Kind().String(),
|
||||
// "type": err.Type().String(),
|
||||
// "value": fmt.Sprintf("%v", err.Value()),
|
||||
// "param": err.Param(),
|
||||
// }
|
||||
}
|
||||
|
||||
// from here you can create your own error messages in whatever language you wish.
|
||||
return
|
||||
}
|
||||
|
||||
// save user to database.
|
||||
})
|
||||
|
||||
// use Postman or whatever to do a POST request
|
||||
// to the http://localhost:8080/user with RAW BODY:
|
||||
/*
|
||||
{
|
||||
"fname": "",
|
||||
"lname": "",
|
||||
"age": 45,
|
||||
"email": "mail@example.com",
|
||||
"favColor": "#000",
|
||||
"addresses": [{
|
||||
"street": "Eavesdown Docks",
|
||||
"planet": "Persphone",
|
||||
"phone": "none",
|
||||
"city": "Unknown"
|
||||
}]
|
||||
}
|
||||
*/
|
||||
// Content-Type to application/json (optionally but good practise).
|
||||
// This request will fail due to the empty `User.FirstName` (fname in json)
|
||||
// and `User.LastName` (lname in json).
|
||||
// Check your iris' application terminal output.
|
||||
app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
|
||||
// UserStructLevelValidation contains custom struct level validations that don't always
|
||||
// make sense at the field validation level. For Example this function validates that either
|
||||
// FirstName or LastName exist; could have done that with a custom field validation but then
|
||||
// would have had to add it to both fields duplicating the logic + overhead, this way it's
|
||||
// only validated once.
|
||||
//
|
||||
// NOTE: you may ask why wouldn't I just do this outside of validator, because doing this way
|
||||
// hooks right into validator and you can combine with validation tags and still have a
|
||||
// common error output format.
|
||||
func UserStructLevelValidation(sl validator.StructLevel) {
|
||||
|
||||
user := sl.Current().Interface().(User)
|
||||
|
||||
if len(user.FirstName) == 0 && len(user.LastName) == 0 {
|
||||
sl.ReportError(user.FirstName, "FirstName", "fname", "fnameorlname", "")
|
||||
sl.ReportError(user.LastName, "LastName", "lname", "fnameorlname", "")
|
||||
}
|
||||
|
||||
// plus can to more, even with different tag than "fnameorlname".
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
```json
|
||||
{
|
||||
"fname": "",
|
||||
"lname": "",
|
||||
"age": 45,
|
||||
"email": "mail@example.com",
|
||||
"favColor": "#000",
|
||||
"addresses": [{
|
||||
"street": "Eavesdown Docks",
|
||||
"planet": "Persphone",
|
||||
"phone": "none",
|
||||
"city": "Unknown"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
First, let's write a simple application which will make use of the HTTP Cookies.
|
||||
### Cookies
|
||||
|
||||
> Are you looking about [http sessions instead?](_examples/sessions)
|
||||
|
||||
Let's write a simple application which will make use of the HTTP Cookies.
|
||||
|
||||
```sh
|
||||
$ cat _examples/cookies/basic/main.go
|
||||
|
@ -795,9 +603,7 @@ func main() {
|
|||
* `ctx.Request().Cookie(name)` is also available, it's the `net/http` approach
|
||||
* Learn more about path parameter's types by clicking [here](_examples/routing/dynamic-path/main.go#L31).
|
||||
|
||||
### httptest
|
||||
|
||||
Next, is the critical part of this section, the **HTTP Testing**.
|
||||
### Testing
|
||||
|
||||
Iris offers an incredible support for the [httpexpect](github.com/iris-contrib/httpexpect), a Testing Framework for web applications. However, you are able to use the standard Go's `net/http/httptest` package as well but in this example we will use the `kataras/iris/httptest`.
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user