All Projects → cssivision → Looli

cssivision / Looli

Licence: mit
a tiny web framework

Programming Languages

go
31211 projects - #10 most used programming language

Projects that are alternatives of or similar to Looli

Middy
🛵 The stylish Node.js middleware engine for AWS Lambda
Stars: ✭ 2,592 (+5660%)
Mutual labels:  middleware, framework
Restana
Super fast and minimalist framework for building REST micro-services.
Stars: ✭ 341 (+657.78%)
Mutual labels:  middleware, framework
Ego
Ego is a full-stack web framework written in Go, lightweight and efficient front-end component solutions, based on gin. The front-end is compiled, does not affect the back-end.
Stars: ✭ 185 (+311.11%)
Mutual labels:  middleware, framework
Foxify
The fast, easy to use & typescript ready web framework for Node.js
Stars: ✭ 138 (+206.67%)
Mutual labels:  middleware, framework
Iris
The fastest HTTP/2 Go Web Framework. AWS Lambda, gRPC, MVC, Unique Router, Websockets, Sessions, Test suite, Dependency Injection and more. A true successor of expressjs and laravel | 谢谢 https://github.com/kataras/iris/issues/1329 |
Stars: ✭ 21,587 (+47871.11%)
Mutual labels:  middleware, framework
Pure Http
✨ The simple web framework for Node.js with zero dependencies.
Stars: ✭ 139 (+208.89%)
Mutual labels:  middleware, framework
Zen
zen is a elegant and lightweight web framework for Go
Stars: ✭ 257 (+471.11%)
Mutual labels:  middleware, framework
Min
A minimalistic web framework with route grouping and middleware chaining
Stars: ✭ 95 (+111.11%)
Mutual labels:  middleware, framework
Gongular
A different approach to Go web frameworks
Stars: ✭ 438 (+873.33%)
Mutual labels:  middleware, framework
Transmittable Thread Local
📌 TransmittableThreadLocal (TTL), the missing Java™ std lib(simple & 0-dependency) for framework/middleware, provide an enhanced InheritableThreadLocal that transmits values between threads even using thread pooling components.
Stars: ✭ 4,678 (+10295.56%)
Mutual labels:  middleware, framework
Typin
Declarative framework for interactive CLI applications
Stars: ✭ 126 (+180%)
Mutual labels:  middleware, framework
Ace tao
ACE and TAO
Stars: ✭ 472 (+948.89%)
Mutual labels:  middleware, framework
Gin
Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
Stars: ✭ 53,971 (+119835.56%)
Mutual labels:  middleware, framework
Goat
[DEPRECATED] 🐐 A minimalistic JSON API server in Go
Stars: ✭ 161 (+257.78%)
Mutual labels:  middleware, framework
Twig
Twig - less is more's web server for golang
Stars: ✭ 98 (+117.78%)
Mutual labels:  middleware, framework
Golf
⛳️ The Golf web framework
Stars: ✭ 248 (+451.11%)
Mutual labels:  middleware, framework
Chubbyphp Framework
A based PSR-15 microframework that also sets maximum flexibility with minimum complexity and easy replaceability of the individual components, but also of the framework.
Stars: ✭ 69 (+53.33%)
Mutual labels:  middleware, framework
Go Web
A new Golang MVC Framework. Like Laravel... but faster!
Stars: ✭ 79 (+75.56%)
Mutual labels:  middleware, framework
Wpemerge
A modern, MVC-powered WordPress as a CMS workflow. 🚀
Stars: ✭ 348 (+673.33%)
Mutual labels:  middleware, framework
Nirvana
Golang Restful API Framework for Productivity
Stars: ✭ 460 (+922.22%)
Mutual labels:  middleware, framework

looli

Build Status Coverage Status License

looli is a minimalist web framework for golang.

Feature

Installation

go get github.com/cssivision/looli

Usage

Router

looli build on the top of router library, which support Named parameters Wildcard parameters Trailing slash redirect Case sensitive Prefix router, for detail.

Using GET, POST, PUT, PATCH, DELETE and OPTIONS

package main

import (
	"github.com/cssivision/looli"
	"log"
)

func main() {
	router := looli.Default()

	router.Get("/a", func(c *looli.Context) {})
	router.Post("/a", func(c *looli.Context) {})
	router.Put("/a", func(c *looli.Context) {})
	router.Delete("/a", func(c *looli.Context) {})
	router.Patch("/a", func(c *looli.Context) {})
	router.Head("/a", func(c *looli.Context) {})
	router.Options("/a", func(c *looli.Context) {})

	log.Fatal(router.Run(":8080"))
}

Named parameter

Named parameters only match a single path segment:

Pattern: /user/:name

 /user/gordon              match
 /user/you                 match
 /user/gordon/profile      no match
 /user/                    no match

Pattern: /:user/:name

 /a/gordon                 match
 /b/you                    match
 /user/gordon/profile      no match
 /user/                    no match
package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    router.Get("/a/:name", func(c *looli.Context) {
        c.Status(200)
        c.String("hello " + c.Param("name") + "!\n")
    })

    http.ListenAndServe(":8080", router)
}

Wildcard pattern

Match everything, therefore they must always be at the end of the pattern:

Pattern: /src/*filepath

 /src/                     match
 /src/somefile.go          match
 /src/subdir/somefile.go   match
package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    router.Get("/a/*filepath", func(c *looli.Context) {
        c.Status(200)
        c.String("hello " + c.Param("filepath") + "!\n")
    })

    http.ListenAndServe(":8080", router)
}

Trailing slash redirect

By default will redirect, which means if we register path /a/b, we can request with /a/b/, conversely also success. redirect will work only in the situation that the request can not found, if both define path /a/b and /a/b/, redirect will not work.

/a/b -> /a/b/
/a/b/ -> /a/b
package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    // default is true, we can forbidden this behavior by set is to false
    // request with /a/ will get 404
    router.SetTrailingSlashRedirect(false)

    router.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world!\n")
    })

    http.ListenAndServe(":8080", router)
}

Case sensitive

By default is not case sensitive, which means if we register path /a/b, request with /A/B will get 404 not found. if we set true, request path with /A/B will success.

package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    // default is false, we can forbidden this behavior by set is to true
    // request with /A/ will success.
    router.SetIgnoreCase(true)

    router.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world!\n")
    })

    http.ListenAndServe(":8080", router)
}

Prefix router

Group router using prefix

package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    v1 := router.Prefix("/v1")
    v1.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world version1\n")
    })

    v2 := router.Prefix("/v2")
    v2.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world version2\n")
    })

    router.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world!\n")
    })

    http.ListenAndServe(":8080", router)
}

Serving static files

package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    // Serve file in the path
    router.StaticFile("/somefile.go", "file/path")

    // Serve files in staic directory
    router.Static("/static", "./static")

    http.ListenAndServe(":8080", router)
}

Context

Context supply some syntactic sugar.

Query and Form

package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    router.Get("/query", func(c *looli.Context) {
        id := c.Query("id")
        name := c.DefaultQuery("name", "cssivision")
        c.Status(200)
        c.String("hello %s, %s\n", id, name)
    })

    router.Post("/form", func(c *looli.Context) {
        name := c.DefaultPostForm("name", "somebody")
        age := c.PostForm("age")
        c.Status(200)
        c.JSON(looli.JSON{
            "name": name,
            "age": age,
        })
    })

    http.ListenAndServe(":8080", router)
}

query

curl 'localhost:8080/query?id=1&name=cssivision'

form

curl -d 'age=21&other=haha' 'localhost:8080/form?id=1&name=cssivision'

Header and Cookie

Use method to operate header and cookie

package main

import (
    "fmt"
    "github.com/cssivision/looli"
    "log"
    "net/http"
)

func main() {
    router := looli.Default()

    router.Get("/header", func(c *looli.Context) {
        fmt.Println(c.Header("User-Agent"))
        c.SetHeader("fake-header", "fake")
        c.Status(200)
        c.String("fake header has setted\n")
    })

    router.Get("/cookie", func(c *looli.Context) {
        val, _ := c.Cookie("fake-cookie")
        fmt.Println(val)
        c.SetCookie(&http.Cookie{
            Name: "fake-cookie",
            Value: "fake",
        })
        c.Status(200)
        c.String("fake cookie has setted\n")
    })

    log.Fatal(router.Run(":8080"))
}

Data binding

To bind a request into a type, use data binding, data can from query, post body. currently support binding of JSON, XML and standard form values (x-www-form-urlencoded and multipart/form-data). When using the Bind-method, the binder depending on the Content-Type header.

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".

The Validation of the incoming data show below.

package main

import (
    "fmt"
    "github.com/cssivision/looli"
    "net/http"
)

type Infomation struct {
    Name string`json:"name"`
    Age int`json:"age"`
}

func (i *Infomation) Validate() error {
    // data validate,
    return nil
}

func main() {
    router := looli.Default()

    // curl 'localhost:8080/query?name=cssivision&age=21'
    router.Get("/query", func(c *looli.Context) {
        query := new(Infomation)
        if err := c.Bind(query); err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println(query.Name)
        fmt.Println(query.Age)
        c.Status(200)
        c.JSON(query)
    })

    // curl -d "name=cssivision&age=21" 'localhost:8080/form'
    router.Post("/form", func(c *looli.Context) {
        form := new(Infomation)
        if err := c.Bind(form); err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println(form.Name)
        fmt.Println(form.Age)
        c.Status(200)
        c.JSON(form)
    })

    // curl  -H "Content-Type: application/json" -X POST -d '{"name":"cssivision","age":21}' localhost:8080/json
    router.Post("/json", func(c *looli.Context) {
        json := new(Infomation)
        if err := c.Bind(json); err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println(json.Name)
        fmt.Println(json.Age)
        c.Status(200)
        c.JSON(json)
    })

    http.ListenAndServe(":8080", router)
}

String JSON rendering

package main

import (
    "github.com/cssivision/looli"
    "net/http"
)

func main() {
    router := looli.Default()

    router.Get("/string", func(c *looli.Context) {
        c.String("the response is %s\n", "string")
    })

    router.Get("/json1", func(c *looli.Context) {
        c.JSON(looli.JSON{
            "name": "cssivision",
            "age": 21,
        })
    })

    router.Get("/json2", func(c *looli.Context) {
        var msg struct {
            Name string`json:"name"`
            Age int`json:"age"`
        }

        msg.Name = "cssivision"
        msg.Age = 21

        c.JSON(msg)
    })

    http.ListenAndServe(":8080", router)
}

HTML rendering

package main

import (
    "github.com/cssivision/looli"
    "net/http"
)

func main() {
    router := looli.Default()

    router.LoadHTMLGlob("templates/*")
    router.Get("/html", func(c *looli.Context) {
        c.HTML("index.tmpl", looli.JSON{
            "title": "my site",
        })
    })

    http.ListenAndServe(":8080", router)
}

templates/index.tmpl

<html>
    <h1>
        {{ .title }}
    </h1>
</html>

Middleware

looli.Default() with middleware Logger() Recover() by default, without middleware use looli.New() instead.

Using middleware

package main

import (
    "net/http"
    "github.com/cssivision/looli"
    "log"
)

func main() {
    router := looli.New()

    // global middleware
    router.Use(looli.Logger())
    router.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world!\n")
    })

    // multi handler for specificed path
    router.Get("/b", func(c *looli.Context) {
        c.String("first handler\n")
    }, func(c *looli.Context) {
        c.String("second handler\n")
    })

    v1 := router.Prefix("/v1")

    // recover middleware only work for /v1 prefix router
    v1.Use(looli.Recover())
    v1.Get("/a", func(c *looli.Context) {
        panic("error!")
        c.Status(200)
        c.String("hello world!\n")
    })

    log.Fatal(http.ListenAndServe(":8080", router))
}

Builtin middlewares

Custome middleware

package main

import (
    "log"
    "net/http"
    "github.com/cssivision/looli"
    "time"
)

func Logger() looli.HandlerFunc {
    return func(c *looli.Context) {
        t := time.Now()
        // before request
        c.Next()
        // after request
        latency := time.Since(t)
        log.Print(latency)
    }
}

func main() {
    router := looli.New()

    // global middleware
    router.Use(Logger())
    router.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world!\n")
    })

    http.ListenAndServe(":8080", router)
}

Licenses

All source code is licensed under the MIT License.

Todo

  • elegant error handle
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].