Skip to content
This repository has been archived by the owner on Dec 23, 2023. It is now read-only.

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
razonyang committed Feb 11, 2020
0 parents commit 699944a
Show file tree
Hide file tree
Showing 22 changed files with 4,179 additions and 0 deletions.
22 changes: 22 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
os:
- linux
- osx
language: go
go:
- 1.9.x
- 1.10.x
- 1.11.x
- 1.12.x
- 1.13.x
- master
jobs:
allow_failures:
- go: master
fast_finish: true
before_install:
- go get github.com/mattn/goveralls
script:
- travis_retry go test -v -covermode=count -coverprofile=coverage.out
- travis_retry go vet ./...
- travis_retry test -z "$(gofmt -d -s . | tee /dev/stderr)"
- travis_retry $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci
29 changes: 29 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
BSD 3-Clause License

Copyright (c) 2020, CleverGo
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
160 changes: 160 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# CleverGo
[![Build Status](https://travis-ci.org/clevergo/clevergo.svg?branch=master)](https://travis-ci.org/clevergo/clevergo)
[![Coverage Status](https://coveralls.io/repos/github/clevergo/clevergo/badge.svg?branch=master)](https://coveralls.io/github/clevergo/clevergo?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/clevergo/clevergo)](https://goreportcard.com/report/github.com/clevergo/clevergo)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue)](https://pkg.go.dev/github.com/clevergo/clevergo)

CleverGo is a trie based high performance HTTP request router.

## Contents

- [Benchmark](#benchmark)
- [Features](#features)
- [Example](#example)
- [Contribute](#contribute)

## Benchmark

Date: 2020/02/11
Lower is better!

[![Benchmark](https://i.imgur.com/iKwcbFn.png)](https://github.com/razonyang/go-http-routing-benchmark)

## Features

- **High Performance:** see [Benchmark](#benchmark) shown above.
- **[Reverse Route Generation](#reverse-route-generation):** there are two ways to generate URL by a route: named route and matched route.
- **Route Group:** as known as subrouter, see [route group](#route-group).
- **Friendly to APIs:** it is easy to design [RESTful APIs](#restful-apis) and versioning your APIs by [route group](#route-group).

## Example

```go
package main

import (
"fmt"
"net/http"

"github.com/clevergo/clevergo"
)

func home(ctx *clevergo.Context) {
ctx.WriteString("hello world")
}

func hello(ctx *clevergo.Context) {
ctx.WriteString(fmt.Sprintf("hello %s", ctx.Params.String("name")))
}

func main() {
router := clevergo.NewRouter()
router.Get("/", home)
router.Get("/hello/:name", hello)
http.ListenAndServe(":8080", router)
}
```

### Params

There are some useful functions to retrieve the parameter value.

```go
func (ctx *clevergo.Context) {
name := ctx.Params.String("name")
page, err := ctx.Params.Int("page")
num, err := ctx.Params.Int64("num")
amount, err := ctx.Params.Uint64("amount")
enable, err := ctx.Params.Bool("enable")
price, err := ctx.Params.Float64("price")
}
```

### Static Files

```go
router.ServeFiles("/static/*filepath", http.Dir("/path/to/static"))

// sometimes, it is useful to treat http.FileServer as NotFoundHandler,
// such as "/favicon.ico".
router.NotFound = http.FileServer(http.Dir("public"))
```

### Reverse Route Generation

```go
queryPost := func (ctx *clevergo.Context) {
// generates URL by matched route.
url, _ := ctx.Route.URL("year", "2020", "month", "02", "slug", "hello world")
}

router.Get("/posts/:year/:month/:slug", queryPost, router.RouteName("post"))

// generates URL by named route.
url, _ := router.URL("post", "year", "2020", "month", "02", "slug", "hello world")
```

### Middleware

Middleware is a function defined as `func (clevergo.Handle) clevergo.Handle`.

```go
authenticator := func (handle clevergo.Handle) clevergo.Handle {
return func(ctx *clevergo.Context) {
// authenticate, terminate request if failed.

// share data between middlewares and handle.
ctx.WithValue("user", "foo")
handle(ctx)
}
}

router.Get("/auth", func(ctx *clevergo.Context) {
ctx.WriteString(fmt.Sprintf("hello %s", ctx.Value("user")))
}, RouteMiddleware(
// middleware for current route.
authenticator,
))
```

Middleware also can be used in route group, see [Route Group](#route-group) for details.

### Route Group

```go
router := clevergo.NewRouter()

api := router.Group("/api", RouteGroupMiddleware(
// middlewares for APIs, such as CORS, authenticator, authorization
))

apiV1 := api.Group("/v1", RouteGroupMiddleware(
// middlewares for v1's APIs
))

apiV2 := api.Group("v2", RouteGroupMiddleware(
// middlewares for v2's APIs
))
```

### RESTful APIs

```go
router.Get("/users", queryUsers)
router.Post("/users", createUser)
router.Get("/users/:id", queryUser)
router.Put("/users/:id", updateUser)
router.Delete("/users/:id", deleteUser)
```

See [Route Group](#route-group) for versioning your APIs.

## Contribute

- Give it a :star: and spread the package.
- [File an issue](https://github.com/clevergo/clevergo/issues/new) for features or bugs.
- Fork and make a pull request.

## Credit

- [julienschmidt/httprouter](https://github.com/julienschmidt/httprouter)
6 changes: 6 additions & 0 deletions clevergo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright 2020 CleverGo. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.

// Package clevergo is a trie based high performance HTTP request router.
package clevergo
93 changes: 93 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright 2020 CleverGo. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.

package clevergo

import (
"context"
"io"
"net/http"
)

// Context contains incoming request, route, params and manages outgoing response.
type Context struct {
Params Params
Route *Route
Request *http.Request
Response http.ResponseWriter
}

func newContext(w http.ResponseWriter, r *http.Request) *Context {
return &Context{
Request: r,
Response: w,
}
}

func (ctx *Context) reset() {
ctx.Params = nil
ctx.Route = nil
ctx.Response = nil
ctx.Request = nil
}

// Error is a shortcut of http.Error.
func (ctx *Context) Error(msg string, code int) {
http.Error(ctx.Response, msg, code)
}

// NotFound is a shortcut of http.NotFound.
func (ctx *Context) NotFound() {
http.NotFound(ctx.Response, ctx.Request)
}

// Redirect is a shortcut of http.Redirect.
func (ctx *Context) Redirect(url string, code int) {
http.Redirect(ctx.Response, ctx.Request, url, code)
}

// SetContentType sets the content type header.
func (ctx *Context) SetContentType(v string) {
ctx.Response.Header().Set("Content-Type", v)
}

// SetContentTypeHTML sets the content type as HTML.
func (ctx *Context) SetContentTypeHTML() {
ctx.SetContentType("text/html; charset=utf-8")
}

// SetContentTypeText sets the content type as text.
func (ctx *Context) SetContentTypeText() {
ctx.SetContentType("text/plain; charset=utf-8")
}

// SetContentTypeJSON sets the content type as JSON.
func (ctx *Context) SetContentTypeJSON() {
ctx.SetContentType("application/json")
}

// SetContentTypeXML sets the content type as XML.
func (ctx *Context) SetContentTypeXML() {
ctx.SetContentType("application/xml")
}

// Write is a shortcut of http.ResponseWriter.Write.
func (ctx *Context) Write(data []byte) (int, error) {
return ctx.Response.Write(data)
}

// WriteString writes the string data to response.
func (ctx *Context) WriteString(data string) (int, error) {
return io.WriteString(ctx.Response, data)
}

// WithValue stores the given value under the given key.
func (ctx *Context) WithValue(key, val interface{}) {
ctx.Request = ctx.Request.WithContext(context.WithValue(ctx.Request.Context(), key, val))
}

// Value returns the value of the given key.
func (ctx *Context) Value(key interface{}) interface{} {
return ctx.Request.Context().Value(key)
}
Loading

0 comments on commit 699944a

Please sign in to comment.