Added Router type
This commit is contained in:
parent
a05f4b2e36
commit
12b5b4a799
@ -7,32 +7,36 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkLookup(b *testing.B) {
|
func BenchmarkLookup(b *testing.B) {
|
||||||
tree := router.Tree[string]{}
|
router := router.New[string]()
|
||||||
routes := loadRoutes("testdata/github.txt")
|
routes := loadRoutes("testdata/github.txt")
|
||||||
|
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
tree.Add(route, "")
|
router.Add(route.method, route.path, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
tree.Lookup(route)
|
router.Lookup(route.method, route.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkLookupNoAlloc(b *testing.B) {
|
func BenchmarkLookupNoAlloc(b *testing.B) {
|
||||||
tree := router.Tree[string]{}
|
router := router.New[string]()
|
||||||
routes := loadRoutes("testdata/github.txt")
|
routes := loadRoutes("testdata/github.txt")
|
||||||
addParameter := func(string, string) {}
|
addParameter := func(string, string) {}
|
||||||
|
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
tree.Add(route, "")
|
router.Add(route.method, route.path, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
for _, route := range routes {
|
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.
|
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
|
## 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
|
BenchmarkLookup-12 30147 39105 ns/op 19488 B/op 337 allocs/op
|
||||||
BenchmarkLookupNoAlloc-12 148033 7993 ns/op 0 B/op 0 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"
|
"git.akyoto.dev/go/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type route struct {
|
||||||
|
method string
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
func TestHello(t *testing.T) {
|
func TestHello(t *testing.T) {
|
||||||
tree := router.Tree[string]{}
|
router := router.New[string]()
|
||||||
|
|
||||||
tree.Add("/hello", "Hello")
|
router.Add("GET", "/hello", "Hello")
|
||||||
tree.Add("/world", "World")
|
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, len(params), 0)
|
||||||
assert.Equal(t, data, "Hello")
|
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, len(params), 0)
|
||||||
assert.Equal(t, data, "World")
|
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, len(params), 0)
|
||||||
assert.Equal(t, data, "")
|
assert.Equal(t, data, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParams(t *testing.T) {
|
func TestParams(t *testing.T) {
|
||||||
tree := router.Tree[string]{}
|
router := router.New[string]()
|
||||||
|
|
||||||
tree.Add("/blog/:slug", "Blog post")
|
router.Add("GET", "/blog/:slug", "Blog post")
|
||||||
tree.Add("/blog/:slug/comments/:id", "Comment")
|
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, len(params), 1)
|
||||||
assert.Equal(t, params[0].Key, "slug")
|
assert.Equal(t, params[0].Key, "slug")
|
||||||
assert.Equal(t, params[0].Value, "hello-world")
|
assert.Equal(t, params[0].Value, "hello-world")
|
||||||
assert.Equal(t, data, "Blog post")
|
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, len(params), 2)
|
||||||
assert.Equal(t, params[0].Key, "slug")
|
assert.Equal(t, params[0].Key, "slug")
|
||||||
assert.Equal(t, params[0].Value, "hello-world")
|
assert.Equal(t, params[0].Value, "hello-world")
|
||||||
@ -51,34 +56,38 @@ func TestParams(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGitHub(t *testing.T) {
|
func TestGitHub(t *testing.T) {
|
||||||
tree := router.Tree[string]{}
|
tree := router.New[string]()
|
||||||
routes := loadRoutes("testdata/github.txt")
|
routes := loadRoutes("testdata/github.txt")
|
||||||
|
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
tree.Add(route, "octocat")
|
tree.Add(route.method, route.path, "octocat")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
data, _ := tree.Lookup(route)
|
data, _ := tree.Lookup(route.method, route.path)
|
||||||
assert.Equal(t, data, "octocat")
|
assert.Equal(t, data, "octocat")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadRoutes(fileName string) []string {
|
func loadRoutes(fileName string) []route {
|
||||||
var routes []string
|
var routes []route
|
||||||
|
|
||||||
for route := range routesInFile(fileName) {
|
for line := range linesInFile(fileName) {
|
||||||
routes = append(routes, route)
|
parts := strings.Split(line, " ")
|
||||||
|
routes = append(routes, route{
|
||||||
|
method: parts[0],
|
||||||
|
path: parts[1],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return routes
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
func routesInFile(fileName string) <-chan string {
|
func linesInFile(fileName string) <-chan string {
|
||||||
routes := make(chan string)
|
lines := make(chan string)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(routes)
|
defer close(lines)
|
||||||
file, err := os.Open(fileName)
|
file, err := os.Open(fileName)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -89,9 +98,9 @@ func routesInFile(fileName string) <-chan string {
|
|||||||
scanner := bufio.NewScanner(file)
|
scanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
for scanner.Scan() {
|
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
|
GET /authorizations
|
||||||
/authorizations/:id
|
GET /authorizations/:id
|
||||||
/applications/:client_id/tokens/:access_token
|
POST /authorizations
|
||||||
/events
|
DELETE /authorizations/:id
|
||||||
/repos/:owner/:repo/events
|
GET /applications/:client_id/tokens/:access_token
|
||||||
/networks/:owner/:repo/events
|
DELETE /applications/:client_id/tokens
|
||||||
/orgs/:org/events
|
DELETE /applications/:client_id/tokens/:access_token
|
||||||
/users/:user/received_events
|
GET /events
|
||||||
/users/:user/received_events/public
|
GET /repos/:owner/:repo/events
|
||||||
/users/:user/events
|
GET /networks/:owner/:repo/events
|
||||||
/users/:user/events/public
|
GET /orgs/:org/events
|
||||||
/users/:user/events/orgs/:org
|
GET /users/:user/received_events
|
||||||
/feeds
|
GET /users/:user/received_events/public
|
||||||
/notifications
|
GET /users/:user/events
|
||||||
/repos/:owner/:repo/notifications
|
GET /users/:user/events/public
|
||||||
/notifications/threads/:id
|
GET /users/:user/events/orgs/:org
|
||||||
/notifications/threads/:id/subscription
|
GET /feeds
|
||||||
/repos/:owner/:repo/stargazers
|
GET /notifications
|
||||||
/users/:user/starred
|
GET /repos/:owner/:repo/notifications
|
||||||
/user/starred
|
PUT /notifications
|
||||||
/user/starred/:owner/:repo
|
PUT /repos/:owner/:repo/notifications
|
||||||
/repos/:owner/:repo/subscribers
|
GET /notifications/threads/:id
|
||||||
/users/:user/subscriptions
|
GET /notifications/threads/:id/subscription
|
||||||
/user/subscriptions
|
PUT /notifications/threads/:id/subscription
|
||||||
/repos/:owner/:repo/subscription
|
DELETE /notifications/threads/:id/subscription
|
||||||
/user/subscriptions/:owner/:repo
|
GET /repos/:owner/:repo/stargazers
|
||||||
/users/:user/gists
|
GET /users/:user/starred
|
||||||
/gists
|
GET /user/starred
|
||||||
/gists/:id
|
GET /user/starred/:owner/:repo
|
||||||
/gists/:id/star
|
PUT /user/starred/:owner/:repo
|
||||||
/repos/:owner/:repo/git/blobs/:sha
|
DELETE /user/starred/:owner/:repo
|
||||||
/repos/:owner/:repo/git/commits/:sha
|
GET /repos/:owner/:repo/subscribers
|
||||||
/repos/:owner/:repo/git/refs
|
GET /users/:user/subscriptions
|
||||||
/repos/:owner/:repo/git/tags/:sha
|
GET /user/subscriptions
|
||||||
/repos/:owner/:repo/git/trees/:sha
|
GET /repos/:owner/:repo/subscription
|
||||||
/issues
|
PUT /repos/:owner/:repo/subscription
|
||||||
/user/issues
|
DELETE /repos/:owner/:repo/subscription
|
||||||
/orgs/:org/issues
|
GET /user/subscriptions/:owner/:repo
|
||||||
/repos/:owner/:repo/issues
|
PUT /user/subscriptions/:owner/:repo
|
||||||
/repos/:owner/:repo/issues/:number
|
DELETE /user/subscriptions/:owner/:repo
|
||||||
/repos/:owner/:repo/assignees
|
GET /users/:user/gists
|
||||||
/repos/:owner/:repo/assignees/:assignee
|
GET /gists
|
||||||
/repos/:owner/:repo/issues/:number/comments
|
GET /gists/:id
|
||||||
/repos/:owner/:repo/issues/:number/events
|
POST /gists
|
||||||
/repos/:owner/:repo/labels
|
PUT /gists/:id/star
|
||||||
/repos/:owner/:repo/labels/:name
|
DELETE /gists/:id/star
|
||||||
/repos/:owner/:repo/issues/:number/labels
|
GET /gists/:id/star
|
||||||
/repos/:owner/:repo/milestones/:number/labels
|
POST /gists/:id/forks
|
||||||
/repos/:owner/:repo/milestones
|
DELETE /gists/:id
|
||||||
/repos/:owner/:repo/milestones/:number
|
GET /repos/:owner/:repo/git/blobs/:sha
|
||||||
/emojis
|
POST /repos/:owner/:repo/git/blobs
|
||||||
/gitignore/templates
|
GET /repos/:owner/:repo/git/commits/:sha
|
||||||
/gitignore/templates/:name
|
POST /repos/:owner/:repo/git/commits
|
||||||
/meta
|
GET /repos/:owner/:repo/git/refs
|
||||||
/rate_limit
|
POST /repos/:owner/:repo/git/refs
|
||||||
/users/:user/orgs
|
GET /repos/:owner/:repo/git/tags/:sha
|
||||||
/user/orgs
|
POST /repos/:owner/:repo/git/tags
|
||||||
/orgs/:org
|
GET /repos/:owner/:repo/git/trees/:sha
|
||||||
/orgs/:org/members
|
POST /repos/:owner/:repo/git/trees
|
||||||
/orgs/:org/members/:user
|
GET /issues
|
||||||
/orgs/:org/public_members
|
GET /user/issues
|
||||||
/orgs/:org/public_members/:user
|
GET /orgs/:org/issues
|
||||||
/orgs/:org/teams
|
GET /repos/:owner/:repo/issues
|
||||||
/teams/:id
|
GET /repos/:owner/:repo/issues/:number
|
||||||
/teams/:id/members
|
POST /repos/:owner/:repo/issues
|
||||||
/teams/:id/members/:user
|
GET /repos/:owner/:repo/assignees
|
||||||
/teams/:id/repos
|
GET /repos/:owner/:repo/assignees/:assignee
|
||||||
/teams/:id/repos/:owner/:repo
|
GET /repos/:owner/:repo/issues/:number/comments
|
||||||
/user/teams
|
POST /repos/:owner/:repo/issues/:number/comments
|
||||||
/repos/:owner/:repo/pulls
|
GET /repos/:owner/:repo/issues/:number/events
|
||||||
/repos/:owner/:repo/pulls/:number
|
GET /repos/:owner/:repo/labels
|
||||||
/repos/:owner/:repo/pulls/:number/commits
|
GET /repos/:owner/:repo/labels/:name
|
||||||
/repos/:owner/:repo/pulls/:number/files
|
POST /repos/:owner/:repo/labels
|
||||||
/repos/:owner/:repo/pulls/:number/merge
|
DELETE /repos/:owner/:repo/labels/:name
|
||||||
/repos/:owner/:repo/pulls/:number/comments
|
GET /repos/:owner/:repo/issues/:number/labels
|
||||||
/user/repos
|
POST /repos/:owner/:repo/issues/:number/labels
|
||||||
/users/:user/repos
|
DELETE /repos/:owner/:repo/issues/:number/labels/:name
|
||||||
/orgs/:org/repos
|
PUT /repos/:owner/:repo/issues/:number/labels
|
||||||
/repositories
|
DELETE /repos/:owner/:repo/issues/:number/labels
|
||||||
/repos/:owner/:repo
|
GET /repos/:owner/:repo/milestones/:number/labels
|
||||||
/repos/:owner/:repo/contributors
|
GET /repos/:owner/:repo/milestones
|
||||||
/repos/:owner/:repo/languages
|
GET /repos/:owner/:repo/milestones/:number
|
||||||
/repos/:owner/:repo/teams
|
POST /repos/:owner/:repo/milestones
|
||||||
/repos/:owner/:repo/tags
|
DELETE /repos/:owner/:repo/milestones/:number
|
||||||
/repos/:owner/:repo/branches
|
GET /emojis
|
||||||
/repos/:owner/:repo/branches/:branch
|
GET /gitignore/templates
|
||||||
/repos/:owner/:repo/collaborators
|
GET /gitignore/templates/:name
|
||||||
/repos/:owner/:repo/collaborators/:user
|
POST /markdown
|
||||||
/repos/:owner/:repo/comments
|
POST /markdown/raw
|
||||||
/repos/:owner/:repo/commits/:sha/comments
|
GET /meta
|
||||||
/repos/:owner/:repo/comments/:id
|
GET /rate_limit
|
||||||
/repos/:owner/:repo/commits
|
GET /users/:user/orgs
|
||||||
/repos/:owner/:repo/commits/:sha
|
GET /user/orgs
|
||||||
/repos/:owner/:repo/readme
|
GET /orgs/:org
|
||||||
/repos/:owner/:repo/keys
|
GET /orgs/:org/members
|
||||||
/repos/:owner/:repo/keys/:id
|
GET /orgs/:org/members/:user
|
||||||
/repos/:owner/:repo/downloads
|
DELETE /orgs/:org/members/:user
|
||||||
/repos/:owner/:repo/downloads/:id
|
GET /orgs/:org/public_members
|
||||||
/repos/:owner/:repo/forks
|
GET /orgs/:org/public_members/:user
|
||||||
/repos/:owner/:repo/hooks
|
PUT /orgs/:org/public_members/:user
|
||||||
/repos/:owner/:repo/hooks/:id
|
DELETE /orgs/:org/public_members/:user
|
||||||
/repos/:owner/:repo/releases
|
GET /orgs/:org/teams
|
||||||
/repos/:owner/:repo/releases/:id
|
GET /teams/:id
|
||||||
/repos/:owner/:repo/releases/:id/assets
|
POST /orgs/:org/teams
|
||||||
/repos/:owner/:repo/stats/contributors
|
DELETE /teams/:id
|
||||||
/repos/:owner/:repo/stats/commit_activity
|
GET /teams/:id/members
|
||||||
/repos/:owner/:repo/stats/code_frequency
|
GET /teams/:id/members/:user
|
||||||
/repos/:owner/:repo/stats/participation
|
PUT /teams/:id/members/:user
|
||||||
/repos/:owner/:repo/stats/punch_card
|
DELETE /teams/:id/members/:user
|
||||||
/repos/:owner/:repo/statuses/:ref
|
GET /teams/:id/repos
|
||||||
/search/repositories
|
GET /teams/:id/repos/:owner/:repo
|
||||||
/search/code
|
PUT /teams/:id/repos/:owner/:repo
|
||||||
/search/issues
|
DELETE /teams/:id/repos/:owner/:repo
|
||||||
/search/users
|
GET /user/teams
|
||||||
/legacy/issues/search/:owner/:repository/:state/:keyword
|
GET /repos/:owner/:repo/pulls
|
||||||
/legacy/repos/search/:keyword
|
GET /repos/:owner/:repo/pulls/:number
|
||||||
/legacy/user/search/:keyword
|
POST /repos/:owner/:repo/pulls
|
||||||
/legacy/user/email/:email
|
GET /repos/:owner/:repo/pulls/:number/commits
|
||||||
/users/:user
|
GET /repos/:owner/:repo/pulls/:number/files
|
||||||
/user
|
GET /repos/:owner/:repo/pulls/:number/merge
|
||||||
/users
|
PUT /repos/:owner/:repo/pulls/:number/merge
|
||||||
/user/emails
|
GET /repos/:owner/:repo/pulls/:number/comments
|
||||||
/users/:user/followers
|
PUT /repos/:owner/:repo/pulls/:number/comments
|
||||||
/user/followers
|
GET /user/repos
|
||||||
/users/:user/following
|
GET /users/:user/repos
|
||||||
/user/following
|
GET /orgs/:org/repos
|
||||||
/user/following/:user
|
GET /repositories
|
||||||
/users/:user/following/:target_user
|
POST /user/repos
|
||||||
/users/:user/keys
|
POST /orgs/:org/repos
|
||||||
/user/keys
|
GET /repos/:owner/:repo
|
||||||
/user/keys/:id
|
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…
x
Reference in New Issue
Block a user