├── .travis.yml ├── LICENSE ├── README.md ├── devrant.go ├── devrant_test.go └── models.go /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.6.3 5 | - tip 6 | 7 | script: go test -v 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Jayesh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # devgorant [![GoDoc](https://godoc.org/github.com/jayeshsolanki93/devgorant?status.svg)](https://godoc.org/github.com/jayeshsolanki93/devgorant) [![Build Status](https://travis-ci.org/jayeshsolanki93/devgorant.svg?branch=master)](https://travis-ci.org/jayeshsolanki93/devgorant) 2 | 3 | Unofficial golang wrapper for the [devRant API](https://www.devrant.io/) 4 | 5 | ## Installation 6 | ```bash 7 | go get github.com/jayeshsolanki93/devgorant 8 | ``` 9 | 10 | ## Usage 11 | Simple implementation to get the user score(points): 12 | 13 | ```go 14 | package main 15 | 16 | import ( 17 | "fmt" 18 | "github.com/jayeshsolanki93/devgorant" 19 | "log" 20 | ) 21 | 22 | func main() { 23 | devrant := devgorant.New() 24 | user, _, err := devrant.Profile("jayeshs") 25 | if err != nil { 26 | log.Fatal(err) 27 | } 28 | fmt.Println(user.Score) 29 | } 30 | ``` 31 | 32 | 33 | ## API Reference 34 | 35 | ### `Rants` : Fetches rants 36 | 37 | **Parameters:** 38 | 39 | | Name | Type | Description | Default | 40 | | ---- | ---- | -------- | ----------- | ------- | 41 | | `sort` | string | Sort by `algo`, `top`, `recent` | `algo` | 42 | | `limit` | integer | Number of rants required. Cannot be more than 50. | 50 | 43 | | `skip` | integer | Number of rants to skip. | 0 | 44 | 45 | **Example:** 46 | ```go 47 | devrant := devgorant.New() 48 | rants, err := devrant.Rants("algo", 20, 0) 49 | ``` 50 | --- 51 | ### `Rant` : Fetches a rant and its comments given a valid rant id 52 | 53 | **Parameters:** 54 | 55 | | Name | Type | Description | Default | 56 | | ---- | ---- | -------- | ----------- | ------- | 57 | | `rantId` | integer | rant_id of a posted rant | | 58 | 59 | **Example:** 60 | ```go 61 | devrant := devgorant.New() 62 | rant, comments, err := devrant.Rant(27317) 63 | ``` 64 | --- 65 | ### `Profile` : Fetches ranter's profile data 66 | 67 | **Parameters:** 68 | 69 | | Name | Type | Description | Default | 70 | | ---- | ---- | -------- | ----------- | ------- | 71 | | `username` | string | a valid username on devRant | | 72 | 73 | **Example:** 74 | ```go 75 | devrant := devgorant.New() 76 | user, content, err := devrant.Profile("jayeshs") 77 | ``` 78 | --- 79 | ### `Search` : Search for rants matching the search term 80 | 81 | **Parameters:** 82 | 83 | | Name | Type | Description | Default | 84 | | ---- | ---- | -------- | ----------- | ------- | 85 | | `term` | string | any string to use as the search term | | 86 | 87 | **Example:** 88 | ```go 89 | devrant := devgorant.New() 90 | rants, err := devrant.Search("golang") 91 | ``` 92 | --- 93 | ### `Surprise` : Returns a random rant 94 | 95 | **Example:** 96 | ```go 97 | devrant := devgorant.New() 98 | rant, err := devrant.Surprise() 99 | ``` 100 | --- 101 | ### `WeeklyRants` : Returns the rants tagged for 'weekly' 102 | 103 | **Example:** 104 | ```go 105 | devrant := devgorant.New() 106 | rants, err := devrant.WeeklyRants() 107 | ``` 108 | --- 109 | 110 | ## Tests 111 | To run the tests locally: 112 | ```bash 113 | go test -v 114 | ``` 115 | 116 | ## TODO 117 | // TODO 118 | -------------------------------------------------------------------------------- /devrant.go: -------------------------------------------------------------------------------- 1 | package devgorant 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "net/http" 8 | ) 9 | 10 | const ( 11 | API = "https://www.devrant.io/api" 12 | APP_VERSION = 3 13 | RANTS_PATH = "%s/devrant/rants?sort=%s&limit=%d&skip=%d&app=%d" 14 | RANT_PATH = "%s/devrant/rants/%d?app=%d" 15 | USER_PATH = "%s/users/%d?app=%d" 16 | USER_ID_PATH = "%s/get-user-id?username=%s&app=%d" 17 | SEARCH_PATH = "%s/devrant/search?term=%s&app=%d" 18 | SURPRISE_PATH = "%s/devrant/rants/surprise?app=%d" 19 | WEEKLY_PATH = "%s/devrant/weekly-rants?app=%d" 20 | ) 21 | 22 | type Client struct { 23 | } 24 | 25 | // Fetches rants 26 | func (c *Client) Rants(sort string, limit int, skip int) ([]RantModel, error) { 27 | if sort == "" { 28 | sort = "algo" 29 | } else if (sort != "algo") && (sort != "recent") && (sort != "top") { 30 | return nil, errors.New("Invalid string in sort method") 31 | } 32 | if limit <= 0 { 33 | limit = 50 34 | } 35 | 36 | url := fmt.Sprintf(RANTS_PATH, API, sort, limit, skip, APP_VERSION) 37 | res, err := http.Get(url) 38 | if err != nil { 39 | return nil, err 40 | } 41 | var data RantsResponse 42 | json.NewDecoder(res.Body).Decode(&data) 43 | if !data.Success && data.Error != "" { 44 | return nil, errors.New(data.Error) 45 | } 46 | return data.Rants, nil 47 | } 48 | 49 | // Fetches a rant and its comments given a valid rant id 50 | func (c *Client) Rant(rantId int) (RantModel, []CommentModel, error) { 51 | url := fmt.Sprintf(RANT_PATH, API, rantId, APP_VERSION) 52 | res, err := http.Get(url) 53 | if err != nil { 54 | return RantModel{}, nil, err 55 | } 56 | var data RantResponse 57 | json.NewDecoder(res.Body).Decode(&data) 58 | if !data.Success && data.Error != "" { 59 | return RantModel{}, nil, errors.New(data.Error) 60 | } 61 | return data.Rant, data.Comments, nil 62 | } 63 | 64 | // Fetches ranter's profile data 65 | func (c *Client) Profile(username string) (UserModel, ContentModel, error) { 66 | userId, err := getUserId(username) 67 | if err != nil { 68 | return UserModel{}, ContentModel{}, err 69 | } 70 | url := fmt.Sprintf(USER_PATH, API, userId, APP_VERSION) 71 | res, err := http.Get(url) 72 | if err != nil { 73 | return UserModel{}, ContentModel{}, err 74 | } 75 | var data UserResponse 76 | json.NewDecoder(res.Body).Decode(&data) 77 | if !data.Success && data.Error != "" { 78 | return UserModel{}, ContentModel{}, errors.New(data.Error) 79 | } 80 | return data.Profile, data.Profile.Content.Content, nil 81 | } 82 | 83 | // Search for rants matching the search term 84 | func (c *Client) Search(term string) ([]RantModel, error) { 85 | url := fmt.Sprintf(SEARCH_PATH, API, term, APP_VERSION) 86 | res, err := http.Get(url) 87 | if err != nil { 88 | return nil, err 89 | } 90 | var data SearchResponse 91 | json.NewDecoder(res.Body).Decode(&data) 92 | if !data.Success && data.Error != "" { 93 | return nil, errors.New(data.Error) 94 | } 95 | return data.Rants, nil 96 | } 97 | 98 | // Returns a random rant 99 | func (c *Client) Surprise() (RantModel, error) { 100 | url := fmt.Sprintf(SURPRISE_PATH, API, APP_VERSION) 101 | res, err := http.Get(url) 102 | if err != nil { 103 | return RantModel{}, err 104 | } 105 | var data RantResponse 106 | json.NewDecoder(res.Body).Decode(&data) 107 | if !data.Success && data.Error != "" { 108 | return RantModel{}, errors.New(data.Error) 109 | } 110 | return data.Rant, nil 111 | } 112 | 113 | // Returns the rants tagged for 'weekly' 114 | func (c *Client) WeeklyRants() ([]RantModel, error) { 115 | url := fmt.Sprintf(WEEKLY_PATH, API, APP_VERSION) 116 | res, err := http.Get(url) 117 | if err != nil { 118 | return nil, err 119 | } 120 | var data RantsResponse 121 | json.NewDecoder(res.Body).Decode(&data) 122 | if !data.Success && data.Error != "" { 123 | return nil, errors.New(data.Error) 124 | } 125 | return data.Rants, nil 126 | } 127 | 128 | // Fetches the userId given a valid username 129 | func getUserId(username string) (int, error) { 130 | url := fmt.Sprintf(USER_ID_PATH, API, username, APP_VERSION) 131 | res, err := http.Get(url) 132 | if err != nil { 133 | return 0, err 134 | } 135 | var data GetUserIdResponse 136 | json.NewDecoder(res.Body).Decode(&data) 137 | if !data.Success && data.Error != "" { 138 | return 0, errors.New(data.Error) 139 | } 140 | return data.UserId, nil 141 | } 142 | 143 | func New() *Client { 144 | return new(Client) 145 | } 146 | -------------------------------------------------------------------------------- /devrant_test.go: -------------------------------------------------------------------------------- 1 | package devgorant_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/jayeshsolanki93/devgorant" 7 | ) 8 | 9 | func TestProfile_jayeshs(t *testing.T) { 10 | devrant := devgorant.New() 11 | user, _, err := devrant.Profile("jayeshs") 12 | if err != nil { 13 | t.Fatalf(`err != nil, got %v`, err) 14 | } 15 | 16 | if got, want := user.Username, "jayeshs"; got != want { 17 | t.Errorf(`user.Username = %s, want %s`, got, want) 18 | } 19 | 20 | if got, want := user.CreatedTime, 1463402493; got != want { 21 | t.Errorf(`user.CreatedTime = %d, want %d`, got, want) 22 | } 23 | } 24 | 25 | func TestRant_27317(t *testing.T) { 26 | devrant := devgorant.New() 27 | rant, _, err := devrant.Rant(27317) 28 | if err != nil { 29 | t.Fatalf(`err != nil, got %v`, err) 30 | } 31 | 32 | if got, want := rant.UserId, 27292; got != want { 33 | t.Errorf(`rant.UserId = %d, want %d`, got, want) 34 | } 35 | } 36 | 37 | func TestRants(t *testing.T) { 38 | devrant := devgorant.New() 39 | rants, err := devrant.Rants("algo", 50, 0) 40 | if err != nil { 41 | t.Fatalf(`err != nil, got %v`, err) 42 | } 43 | 44 | if got, want := len(rants), 50; got != want { 45 | t.Errorf(`len(rants) = %d, want > 0`, got) 46 | } 47 | } 48 | 49 | // TODO: More tests 50 | -------------------------------------------------------------------------------- /models.go: -------------------------------------------------------------------------------- 1 | package devgorant 2 | 3 | type RantModel struct { 4 | Id int `json:"id"` 5 | Text string `json:"text"` 6 | Upvotes int `json:"num_upvotes"` 7 | Downvotes int `json:"num_downvotes"` 8 | Score int `json:"score"` 9 | CreatedTime int `json:"created_time"` 10 | AttachedImage ImageModel `json:"attached_image"` 11 | NumComments int `json:"num_comments"` 12 | Tags []string `json:"tags"` 13 | UserId int `json:"user_id"` 14 | UserUsername string `json:"user_username"` 15 | UserScore int `json:"user_score"` 16 | } 17 | 18 | type UserModel struct { 19 | Username string `json:"username"` 20 | Score int `json:"score"` 21 | About string `json:"about"` 22 | Location string `json:"location"` 23 | CreatedTime int `json:"created_time"` 24 | Skills string `json:"skills"` 25 | Github string `json:"github"` 26 | Content struct { 27 | Content ContentModel `json:"content"` 28 | } `json:"content"` 29 | } 30 | 31 | type ImageModel struct { 32 | Url string `json:"url"` 33 | Width int `json:"width"` 34 | Height int `json:"height"` 35 | } 36 | 37 | type CommentModel struct { 38 | Id int `json:"id"` 39 | RantId int `json:"rant_id"` 40 | Body string `json:"body"` 41 | Upvotes int `json:"num_upvotes"` 42 | Downvotes int `json:"num_downvotes"` 43 | Score int `json:"score"` 44 | CreatedTime int `json:"created_time"` 45 | UserId int `json:"user_id"` 46 | UserUsername string `json:"user_username"` 47 | UserScore int `json:"user_score"` 48 | } 49 | 50 | type ContentModel struct { 51 | Rants []RantModel `json:"rants"` 52 | Upvoted []RantModel `json:"upvoted"` 53 | Comments []CommentModel `json:"comments"` 54 | Favorites []RantModel `json:"favorites"` 55 | } 56 | 57 | type NewsModel struct { 58 | Id int `json:"id"` 59 | Type string `json:"type"` 60 | Headline string `json:"headline"` 61 | Body string `json:"body"` 62 | Footer string `json:"footer"` 63 | Height int `json:"height"` 64 | Action string `json:"action"` 65 | } 66 | 67 | type RantsResponse struct { 68 | Success bool `json:"success"` 69 | Error string `json:"error"` 70 | Rants []RantModel `json:"rants"` 71 | Settings string `json:"settings"` 72 | Set string `json:"set"` 73 | Wrw int `json:"wrw"` 74 | News NewsModel `json:"news"` 75 | } 76 | 77 | type RantResponse struct { 78 | Success bool `json:"success"` 79 | Error string `json:"error"` 80 | Rant RantModel `json:"rant"` 81 | Comments []CommentModel `json:"comments"` 82 | } 83 | 84 | type UserResponse struct { 85 | Success bool `json:"success"` 86 | Error string `json:"error"` 87 | Profile UserModel `json:"profile"` 88 | } 89 | 90 | type SearchResponse struct { 91 | Success bool `json:"success"` 92 | Error string `json:"error"` 93 | Rants []RantModel `json:"results"` 94 | } 95 | 96 | type GetUserIdResponse struct { 97 | Success bool `json:"success"` 98 | Error string `json:"error"` 99 | UserId int `json:"user_id"` 100 | } 101 | --------------------------------------------------------------------------------