Added Router type
This commit is contained in:
parent
a05f4b2e36
commit
12b5b4a799
@ -7,32 +7,36 @@ import (
|
||||
)
|
||||
|
||||
func BenchmarkLookup(b *testing.B) {
|
||||
tree := router.Tree[string]{}
|
||||
router := router.New[string]()
|
||||
routes := loadRoutes("testdata/github.txt")
|
||||
|
||||
for _, route := range routes {
|
||||
tree.Add(route, "")
|
||||
router.Add(route.method, route.path, "")
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, route := range routes {
|
||||
tree.Lookup(route)
|
||||
router.Lookup(route.method, route.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLookupNoAlloc(b *testing.B) {
|
||||
tree := router.Tree[string]{}
|
||||
router := router.New[string]()
|
||||
routes := loadRoutes("testdata/github.txt")
|
||||
addParameter := func(string, string) {}
|
||||
|
||||
for _, route := range routes {
|
||||
tree.Add(route, "")
|
||||
router.Add(route.method, route.path, "")
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, route := range routes {
|
||||
tree.LookupNoAlloc(route, addParameter)
|
||||
router.LookupNoAlloc(route.method, route.path, addParameter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
README.md
17
README.md
@ -2,11 +2,22 @@
|
||||
|
||||
HTTP router based on radix trees.
|
||||
|
||||
## Example
|
||||
|
||||
We can save any type of data inside the router. Here is an example storing strings for each route:
|
||||
|
||||
```go
|
||||
router := router.New[string]()
|
||||
|
||||
router.Add("GET", "/hello", "Hello")
|
||||
router.Add("GET", "/world", "World")
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
Loading and requesting every single route in [github.txt](testdata/github.txt):
|
||||
Requesting every single route in [github.txt](testdata/github.txt):
|
||||
|
||||
```
|
||||
BenchmarkLookup-12 50715 23207 ns/op 11649 B/op 204 allocs/op
|
||||
BenchmarkLookupNoAlloc-12 148033 7993 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkLookup-12 30147 39105 ns/op 19488 B/op 337 allocs/op
|
||||
BenchmarkLookupNoAlloc-12 85166 14411 ns/op 0 B/op 0 allocs/op
|
||||
```
|
84
Router.go
Normal file
84
Router.go
Normal file
@ -0,0 +1,84 @@
|
||||
package router
|
||||
|
||||
// Router is a high-performance router.
|
||||
type Router[T comparable] struct {
|
||||
get Tree[T]
|
||||
post Tree[T]
|
||||
delete Tree[T]
|
||||
put Tree[T]
|
||||
patch Tree[T]
|
||||
head Tree[T]
|
||||
connect Tree[T]
|
||||
trace Tree[T]
|
||||
options Tree[T]
|
||||
}
|
||||
|
||||
// New creates a new router containing trees for every HTTP method.
|
||||
func New[T comparable]() *Router[T] {
|
||||
return &Router[T]{}
|
||||
}
|
||||
|
||||
// Add registers a new handler for the given method and path.
|
||||
func (router *Router[T]) Add(method string, path string, handler T) {
|
||||
tree := router.selectTree(method)
|
||||
tree.Add(path, handler)
|
||||
}
|
||||
|
||||
// Lookup finds the handler and parameters for the given route.
|
||||
func (router *Router[T]) Lookup(method string, path string) (T, []Parameter) {
|
||||
if method[0] == 'G' {
|
||||
return router.get.Lookup(path)
|
||||
}
|
||||
|
||||
tree := router.selectTree(method)
|
||||
return tree.Lookup(path)
|
||||
}
|
||||
|
||||
// LookupNoAlloc finds the handler and parameters for the given route without using any memory allocations.
|
||||
func (router *Router[T]) LookupNoAlloc(method string, path string, addParameter func(string, string)) T {
|
||||
if method[0] == 'G' {
|
||||
return router.get.LookupNoAlloc(path, addParameter)
|
||||
}
|
||||
|
||||
tree := router.selectTree(method)
|
||||
return tree.LookupNoAlloc(path, addParameter)
|
||||
}
|
||||
|
||||
// Bind traverses all trees and calls the given function on every node.
|
||||
func (router *Router[T]) Bind(transform func(T) T) {
|
||||
router.get.Bind(transform)
|
||||
router.post.Bind(transform)
|
||||
router.delete.Bind(transform)
|
||||
router.put.Bind(transform)
|
||||
router.patch.Bind(transform)
|
||||
router.head.Bind(transform)
|
||||
router.connect.Bind(transform)
|
||||
router.trace.Bind(transform)
|
||||
router.options.Bind(transform)
|
||||
}
|
||||
|
||||
// selectTree returns the tree by the given HTTP method.
|
||||
func (router *Router[T]) selectTree(method string) *Tree[T] {
|
||||
switch method {
|
||||
case "GET":
|
||||
return &router.get
|
||||
case "POST":
|
||||
return &router.post
|
||||
case "DELETE":
|
||||
return &router.delete
|
||||
case "PUT":
|
||||
return &router.put
|
||||
case "PATCH":
|
||||
return &router.patch
|
||||
case "HEAD":
|
||||
return &router.head
|
||||
case "CONNECT":
|
||||
return &router.connect
|
||||
case "TRACE":
|
||||
return &router.trace
|
||||
case "OPTIONS":
|
||||
return &router.options
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
@ -10,38 +10,43 @@ import (
|
||||
"git.akyoto.dev/go/router"
|
||||
)
|
||||
|
||||
type route struct {
|
||||
method string
|
||||
path string
|
||||
}
|
||||
|
||||
func TestHello(t *testing.T) {
|
||||
tree := router.Tree[string]{}
|
||||
router := router.New[string]()
|
||||
|
||||
tree.Add("/hello", "Hello")
|
||||
tree.Add("/world", "World")
|
||||
router.Add("GET", "/hello", "Hello")
|
||||
router.Add("GET", "/world", "World")
|
||||
|
||||
data, params := tree.Lookup("/hello")
|
||||
data, params := router.Lookup("GET", "/hello")
|
||||
assert.Equal(t, len(params), 0)
|
||||
assert.Equal(t, data, "Hello")
|
||||
|
||||
data, params = tree.Lookup("/world")
|
||||
data, params = router.Lookup("GET", "/world")
|
||||
assert.Equal(t, len(params), 0)
|
||||
assert.Equal(t, data, "World")
|
||||
|
||||
data, params = tree.Lookup("/404")
|
||||
data, params = router.Lookup("GET", "/404")
|
||||
assert.Equal(t, len(params), 0)
|
||||
assert.Equal(t, data, "")
|
||||
}
|
||||
|
||||
func TestParams(t *testing.T) {
|
||||
tree := router.Tree[string]{}
|
||||
router := router.New[string]()
|
||||
|
||||
tree.Add("/blog/:slug", "Blog post")
|
||||
tree.Add("/blog/:slug/comments/:id", "Comment")
|
||||
router.Add("GET", "/blog/:slug", "Blog post")
|
||||
router.Add("GET", "/blog/:slug/comments/:id", "Comment")
|
||||
|
||||
data, params := tree.Lookup("/blog/hello-world")
|
||||
data, params := router.Lookup("GET", "/blog/hello-world")
|
||||
assert.Equal(t, len(params), 1)
|
||||
assert.Equal(t, params[0].Key, "slug")
|
||||
assert.Equal(t, params[0].Value, "hello-world")
|
||||
assert.Equal(t, data, "Blog post")
|
||||
|
||||
data, params = tree.Lookup("/blog/hello-world/comments/123")
|
||||
data, params = router.Lookup("GET", "/blog/hello-world/comments/123")
|
||||
assert.Equal(t, len(params), 2)
|
||||
assert.Equal(t, params[0].Key, "slug")
|
||||
assert.Equal(t, params[0].Value, "hello-world")
|
||||
@ -51,34 +56,38 @@ func TestParams(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGitHub(t *testing.T) {
|
||||
tree := router.Tree[string]{}
|
||||
tree := router.New[string]()
|
||||
routes := loadRoutes("testdata/github.txt")
|
||||
|
||||
for _, route := range routes {
|
||||
tree.Add(route, "octocat")
|
||||
tree.Add(route.method, route.path, "octocat")
|
||||
}
|
||||
|
||||
for _, route := range routes {
|
||||
data, _ := tree.Lookup(route)
|
||||
data, _ := tree.Lookup(route.method, route.path)
|
||||
assert.Equal(t, data, "octocat")
|
||||
}
|
||||
}
|
||||
|
||||
func loadRoutes(fileName string) []string {
|
||||
var routes []string
|
||||
func loadRoutes(fileName string) []route {
|
||||
var routes []route
|
||||
|
||||
for route := range routesInFile(fileName) {
|
||||
routes = append(routes, route)
|
||||
for line := range linesInFile(fileName) {
|
||||
parts := strings.Split(line, " ")
|
||||
routes = append(routes, route{
|
||||
method: parts[0],
|
||||
path: parts[1],
|
||||
})
|
||||
}
|
||||
|
||||
return routes
|
||||
}
|
||||
|
||||
func routesInFile(fileName string) <-chan string {
|
||||
routes := make(chan string)
|
||||
func linesInFile(fileName string) <-chan string {
|
||||
lines := make(chan string)
|
||||
|
||||
go func() {
|
||||
defer close(routes)
|
||||
defer close(lines)
|
||||
file, err := os.Open(fileName)
|
||||
|
||||
if err != nil {
|
||||
@ -89,9 +98,9 @@ func routesInFile(fileName string) <-chan string {
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
for scanner.Scan() {
|
||||
routes <- strings.TrimSpace(scanner.Text())
|
||||
lines <- strings.TrimSpace(scanner.Text())
|
||||
}
|
||||
}()
|
||||
|
||||
return routes
|
||||
return lines
|
||||
}
|
334
testdata/github.txt
vendored
334
testdata/github.txt
vendored
@ -1,131 +1,203 @@
|
||||
/authorizations
|
||||
/authorizations/:id
|
||||
/applications/:client_id/tokens/:access_token
|
||||
/events
|
||||
/repos/:owner/:repo/events
|
||||
/networks/:owner/:repo/events
|
||||
/orgs/:org/events
|
||||
/users/:user/received_events
|
||||
/users/:user/received_events/public
|
||||
/users/:user/events
|
||||
/users/:user/events/public
|
||||
/users/:user/events/orgs/:org
|
||||
/feeds
|
||||
/notifications
|
||||
/repos/:owner/:repo/notifications
|
||||
/notifications/threads/:id
|
||||
/notifications/threads/:id/subscription
|
||||
/repos/:owner/:repo/stargazers
|
||||
/users/:user/starred
|
||||
/user/starred
|
||||
/user/starred/:owner/:repo
|
||||
/repos/:owner/:repo/subscribers
|
||||
/users/:user/subscriptions
|
||||
/user/subscriptions
|
||||
/repos/:owner/:repo/subscription
|
||||
/user/subscriptions/:owner/:repo
|
||||
/users/:user/gists
|
||||
/gists
|
||||
/gists/:id
|
||||
/gists/:id/star
|
||||
/repos/:owner/:repo/git/blobs/:sha
|
||||
/repos/:owner/:repo/git/commits/:sha
|
||||
/repos/:owner/:repo/git/refs
|
||||
/repos/:owner/:repo/git/tags/:sha
|
||||
/repos/:owner/:repo/git/trees/:sha
|
||||
/issues
|
||||
/user/issues
|
||||
/orgs/:org/issues
|
||||
/repos/:owner/:repo/issues
|
||||
/repos/:owner/:repo/issues/:number
|
||||
/repos/:owner/:repo/assignees
|
||||
/repos/:owner/:repo/assignees/:assignee
|
||||
/repos/:owner/:repo/issues/:number/comments
|
||||
/repos/:owner/:repo/issues/:number/events
|
||||
/repos/:owner/:repo/labels
|
||||
/repos/:owner/:repo/labels/:name
|
||||
/repos/:owner/:repo/issues/:number/labels
|
||||
/repos/:owner/:repo/milestones/:number/labels
|
||||
/repos/:owner/:repo/milestones
|
||||
/repos/:owner/:repo/milestones/:number
|
||||
/emojis
|
||||
/gitignore/templates
|
||||
/gitignore/templates/:name
|
||||
/meta
|
||||
/rate_limit
|
||||
/users/:user/orgs
|
||||
/user/orgs
|
||||
/orgs/:org
|
||||
/orgs/:org/members
|
||||
/orgs/:org/members/:user
|
||||
/orgs/:org/public_members
|
||||
/orgs/:org/public_members/:user
|
||||
/orgs/:org/teams
|
||||
/teams/:id
|
||||
/teams/:id/members
|
||||
/teams/:id/members/:user
|
||||
/teams/:id/repos
|
||||
/teams/:id/repos/:owner/:repo
|
||||
/user/teams
|
||||
/repos/:owner/:repo/pulls
|
||||
/repos/:owner/:repo/pulls/:number
|
||||
/repos/:owner/:repo/pulls/:number/commits
|
||||
/repos/:owner/:repo/pulls/:number/files
|
||||
/repos/:owner/:repo/pulls/:number/merge
|
||||
/repos/:owner/:repo/pulls/:number/comments
|
||||
/user/repos
|
||||
/users/:user/repos
|
||||
/orgs/:org/repos
|
||||
/repositories
|
||||
/repos/:owner/:repo
|
||||
/repos/:owner/:repo/contributors
|
||||
/repos/:owner/:repo/languages
|
||||
/repos/:owner/:repo/teams
|
||||
/repos/:owner/:repo/tags
|
||||
/repos/:owner/:repo/branches
|
||||
/repos/:owner/:repo/branches/:branch
|
||||
/repos/:owner/:repo/collaborators
|
||||
/repos/:owner/:repo/collaborators/:user
|
||||
/repos/:owner/:repo/comments
|
||||
/repos/:owner/:repo/commits/:sha/comments
|
||||
/repos/:owner/:repo/comments/:id
|
||||
/repos/:owner/:repo/commits
|
||||
/repos/:owner/:repo/commits/:sha
|
||||
/repos/:owner/:repo/readme
|
||||
/repos/:owner/:repo/keys
|
||||
/repos/:owner/:repo/keys/:id
|
||||
/repos/:owner/:repo/downloads
|
||||
/repos/:owner/:repo/downloads/:id
|
||||
/repos/:owner/:repo/forks
|
||||
/repos/:owner/:repo/hooks
|
||||
/repos/:owner/:repo/hooks/:id
|
||||
/repos/:owner/:repo/releases
|
||||
/repos/:owner/:repo/releases/:id
|
||||
/repos/:owner/:repo/releases/:id/assets
|
||||
/repos/:owner/:repo/stats/contributors
|
||||
/repos/:owner/:repo/stats/commit_activity
|
||||
/repos/:owner/:repo/stats/code_frequency
|
||||
/repos/:owner/:repo/stats/participation
|
||||
/repos/:owner/:repo/stats/punch_card
|
||||
/repos/:owner/:repo/statuses/:ref
|
||||
/search/repositories
|
||||
/search/code
|
||||
/search/issues
|
||||
/search/users
|
||||
/legacy/issues/search/:owner/:repository/:state/:keyword
|
||||
/legacy/repos/search/:keyword
|
||||
/legacy/user/search/:keyword
|
||||
/legacy/user/email/:email
|
||||
/users/:user
|
||||
/user
|
||||
/users
|
||||
/user/emails
|
||||
/users/:user/followers
|
||||
/user/followers
|
||||
/users/:user/following
|
||||
/user/following
|
||||
/user/following/:user
|
||||
/users/:user/following/:target_user
|
||||
/users/:user/keys
|
||||
/user/keys
|
||||
/user/keys/:id
|
||||
GET /authorizations
|
||||
GET /authorizations/:id
|
||||
POST /authorizations
|
||||
DELETE /authorizations/:id
|
||||
GET /applications/:client_id/tokens/:access_token
|
||||
DELETE /applications/:client_id/tokens
|
||||
DELETE /applications/:client_id/tokens/:access_token
|
||||
GET /events
|
||||
GET /repos/:owner/:repo/events
|
||||
GET /networks/:owner/:repo/events
|
||||
GET /orgs/:org/events
|
||||
GET /users/:user/received_events
|
||||
GET /users/:user/received_events/public
|
||||
GET /users/:user/events
|
||||
GET /users/:user/events/public
|
||||
GET /users/:user/events/orgs/:org
|
||||
GET /feeds
|
||||
GET /notifications
|
||||
GET /repos/:owner/:repo/notifications
|
||||
PUT /notifications
|
||||
PUT /repos/:owner/:repo/notifications
|
||||
GET /notifications/threads/:id
|
||||
GET /notifications/threads/:id/subscription
|
||||
PUT /notifications/threads/:id/subscription
|
||||
DELETE /notifications/threads/:id/subscription
|
||||
GET /repos/:owner/:repo/stargazers
|
||||
GET /users/:user/starred
|
||||
GET /user/starred
|
||||
GET /user/starred/:owner/:repo
|
||||
PUT /user/starred/:owner/:repo
|
||||
DELETE /user/starred/:owner/:repo
|
||||
GET /repos/:owner/:repo/subscribers
|
||||
GET /users/:user/subscriptions
|
||||
GET /user/subscriptions
|
||||
GET /repos/:owner/:repo/subscription
|
||||
PUT /repos/:owner/:repo/subscription
|
||||
DELETE /repos/:owner/:repo/subscription
|
||||
GET /user/subscriptions/:owner/:repo
|
||||
PUT /user/subscriptions/:owner/:repo
|
||||
DELETE /user/subscriptions/:owner/:repo
|
||||
GET /users/:user/gists
|
||||
GET /gists
|
||||
GET /gists/:id
|
||||
POST /gists
|
||||
PUT /gists/:id/star
|
||||
DELETE /gists/:id/star
|
||||
GET /gists/:id/star
|
||||
POST /gists/:id/forks
|
||||
DELETE /gists/:id
|
||||
GET /repos/:owner/:repo/git/blobs/:sha
|
||||
POST /repos/:owner/:repo/git/blobs
|
||||
GET /repos/:owner/:repo/git/commits/:sha
|
||||
POST /repos/:owner/:repo/git/commits
|
||||
GET /repos/:owner/:repo/git/refs
|
||||
POST /repos/:owner/:repo/git/refs
|
||||
GET /repos/:owner/:repo/git/tags/:sha
|
||||
POST /repos/:owner/:repo/git/tags
|
||||
GET /repos/:owner/:repo/git/trees/:sha
|
||||
POST /repos/:owner/:repo/git/trees
|
||||
GET /issues
|
||||
GET /user/issues
|
||||
GET /orgs/:org/issues
|
||||
GET /repos/:owner/:repo/issues
|
||||
GET /repos/:owner/:repo/issues/:number
|
||||
POST /repos/:owner/:repo/issues
|
||||
GET /repos/:owner/:repo/assignees
|
||||
GET /repos/:owner/:repo/assignees/:assignee
|
||||
GET /repos/:owner/:repo/issues/:number/comments
|
||||
POST /repos/:owner/:repo/issues/:number/comments
|
||||
GET /repos/:owner/:repo/issues/:number/events
|
||||
GET /repos/:owner/:repo/labels
|
||||
GET /repos/:owner/:repo/labels/:name
|
||||
POST /repos/:owner/:repo/labels
|
||||
DELETE /repos/:owner/:repo/labels/:name
|
||||
GET /repos/:owner/:repo/issues/:number/labels
|
||||
POST /repos/:owner/:repo/issues/:number/labels
|
||||
DELETE /repos/:owner/:repo/issues/:number/labels/:name
|
||||
PUT /repos/:owner/:repo/issues/:number/labels
|
||||
DELETE /repos/:owner/:repo/issues/:number/labels
|
||||
GET /repos/:owner/:repo/milestones/:number/labels
|
||||
GET /repos/:owner/:repo/milestones
|
||||
GET /repos/:owner/:repo/milestones/:number
|
||||
POST /repos/:owner/:repo/milestones
|
||||
DELETE /repos/:owner/:repo/milestones/:number
|
||||
GET /emojis
|
||||
GET /gitignore/templates
|
||||
GET /gitignore/templates/:name
|
||||
POST /markdown
|
||||
POST /markdown/raw
|
||||
GET /meta
|
||||
GET /rate_limit
|
||||
GET /users/:user/orgs
|
||||
GET /user/orgs
|
||||
GET /orgs/:org
|
||||
GET /orgs/:org/members
|
||||
GET /orgs/:org/members/:user
|
||||
DELETE /orgs/:org/members/:user
|
||||
GET /orgs/:org/public_members
|
||||
GET /orgs/:org/public_members/:user
|
||||
PUT /orgs/:org/public_members/:user
|
||||
DELETE /orgs/:org/public_members/:user
|
||||
GET /orgs/:org/teams
|
||||
GET /teams/:id
|
||||
POST /orgs/:org/teams
|
||||
DELETE /teams/:id
|
||||
GET /teams/:id/members
|
||||
GET /teams/:id/members/:user
|
||||
PUT /teams/:id/members/:user
|
||||
DELETE /teams/:id/members/:user
|
||||
GET /teams/:id/repos
|
||||
GET /teams/:id/repos/:owner/:repo
|
||||
PUT /teams/:id/repos/:owner/:repo
|
||||
DELETE /teams/:id/repos/:owner/:repo
|
||||
GET /user/teams
|
||||
GET /repos/:owner/:repo/pulls
|
||||
GET /repos/:owner/:repo/pulls/:number
|
||||
POST /repos/:owner/:repo/pulls
|
||||
GET /repos/:owner/:repo/pulls/:number/commits
|
||||
GET /repos/:owner/:repo/pulls/:number/files
|
||||
GET /repos/:owner/:repo/pulls/:number/merge
|
||||
PUT /repos/:owner/:repo/pulls/:number/merge
|
||||
GET /repos/:owner/:repo/pulls/:number/comments
|
||||
PUT /repos/:owner/:repo/pulls/:number/comments
|
||||
GET /user/repos
|
||||
GET /users/:user/repos
|
||||
GET /orgs/:org/repos
|
||||
GET /repositories
|
||||
POST /user/repos
|
||||
POST /orgs/:org/repos
|
||||
GET /repos/:owner/:repo
|
||||
GET /repos/:owner/:repo/contributors
|
||||
GET /repos/:owner/:repo/languages
|
||||
GET /repos/:owner/:repo/teams
|
||||
GET /repos/:owner/:repo/tags
|
||||
GET /repos/:owner/:repo/branches
|
||||
GET /repos/:owner/:repo/branches/:branch
|
||||
DELETE /repos/:owner/:repo
|
||||
GET /repos/:owner/:repo/collaborators
|
||||
GET /repos/:owner/:repo/collaborators/:user
|
||||
PUT /repos/:owner/:repo/collaborators/:user
|
||||
DELETE /repos/:owner/:repo/collaborators/:user
|
||||
GET /repos/:owner/:repo/comments
|
||||
GET /repos/:owner/:repo/commits/:sha/comments
|
||||
POST /repos/:owner/:repo/commits/:sha/comments
|
||||
GET /repos/:owner/:repo/comments/:id
|
||||
DELETE /repos/:owner/:repo/comments/:id
|
||||
GET /repos/:owner/:repo/commits
|
||||
GET /repos/:owner/:repo/commits/:sha
|
||||
GET /repos/:owner/:repo/readme
|
||||
GET /repos/:owner/:repo/keys
|
||||
GET /repos/:owner/:repo/keys/:id
|
||||
POST /repos/:owner/:repo/keys
|
||||
DELETE /repos/:owner/:repo/keys/:id
|
||||
GET /repos/:owner/:repo/downloads
|
||||
GET /repos/:owner/:repo/downloads/:id
|
||||
DELETE /repos/:owner/:repo/downloads/:id
|
||||
GET /repos/:owner/:repo/forks
|
||||
POST /repos/:owner/:repo/forks
|
||||
GET /repos/:owner/:repo/hooks
|
||||
GET /repos/:owner/:repo/hooks/:id
|
||||
POST /repos/:owner/:repo/hooks
|
||||
POST /repos/:owner/:repo/hooks/:id/tests
|
||||
DELETE /repos/:owner/:repo/hooks/:id
|
||||
POST /repos/:owner/:repo/merges
|
||||
GET /repos/:owner/:repo/releases
|
||||
GET /repos/:owner/:repo/releases/:id
|
||||
POST /repos/:owner/:repo/releases
|
||||
DELETE /repos/:owner/:repo/releases/:id
|
||||
GET /repos/:owner/:repo/releases/:id/assets
|
||||
GET /repos/:owner/:repo/stats/contributors
|
||||
GET /repos/:owner/:repo/stats/commit_activity
|
||||
GET /repos/:owner/:repo/stats/code_frequency
|
||||
GET /repos/:owner/:repo/stats/participation
|
||||
GET /repos/:owner/:repo/stats/punch_card
|
||||
GET /repos/:owner/:repo/statuses/:ref
|
||||
POST /repos/:owner/:repo/statuses/:ref
|
||||
GET /search/repositories
|
||||
GET /search/code
|
||||
GET /search/issues
|
||||
GET /search/users
|
||||
GET /legacy/issues/search/:owner/:repository/:state/:keyword
|
||||
GET /legacy/repos/search/:keyword
|
||||
GET /legacy/user/search/:keyword
|
||||
GET /legacy/user/email/:email
|
||||
GET /users/:user
|
||||
GET /user
|
||||
GET /users
|
||||
GET /user/emails
|
||||
POST /user/emails
|
||||
DELETE /user/emails
|
||||
GET /users/:user/followers
|
||||
GET /user/followers
|
||||
GET /users/:user/following
|
||||
GET /user/following
|
||||
GET /user/following/:user
|
||||
GET /users/:user/following/:target_user
|
||||
PUT /user/following/:user
|
||||
DELETE /user/following/:user
|
||||
GET /users/:user/keys
|
||||
GET /user/keys
|
||||
GET /user/keys/:id
|
||||
POST /user/keys
|
||||
DELETE /user/keys/:id
|
Loading…
Reference in New Issue
Block a user