├── .github └── workflows │ └── go.yml ├── .gitignore ├── LICENSE ├── README.md ├── go.mod ├── go.sum ├── gowikidata.go ├── gowikidata_test.go └── models.go /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | pull_request: 5 | branches: [ master ] 6 | push: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Set up Go 17 | uses: actions/setup-go@v2 18 | with: 19 | go-version: 1.16 20 | 21 | - name: Test 22 | run: go test -v ./... 23 | 24 | - name: Build 25 | run: go build -v ./... 26 | 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/go 3 | # Edit at https://www.gitignore.io/?templates=go 4 | 5 | ### Go ### 6 | # Binaries for programs and plugins 7 | *.exe 8 | *.exe~ 9 | *.dll 10 | *.so 11 | *.dylib 12 | 13 | # Test binary, built with `go test -c` 14 | *.test 15 | 16 | # Output of the go coverage tool, specifically when used with LiteIDE 17 | *.out 18 | 19 | ### Go Patch ### 20 | /vendor/ 21 | /files/* 22 | /Godeps/ 23 | /.idea/ 24 | # End of https://www.gitignore.io/api/go 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Navid Zarepak 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 | # go-wikidata 2 | 3 | [![GoDoc](https://godoc.org/github.com/Navid2zp/go-wikidata?status.svg)](https://pkg.go.dev/github.com/Navid2zp/go-wikidata?tab=doc) 4 | [![Build](https://img.shields.io/github/workflow/status/Navid2zp/go-wikidata/Test)](https://github.com/Navid2zp/go-wikidata/actions/workflows/go.yml) 5 | [![Go Report Card](https://goreportcard.com/badge/github.com/Navid2zp/go-wikidata)](https://goreportcard.com/report/github.com/Navid2zp/go-wikidata) 6 | [![GitHub license](https://img.shields.io/github/license/Navid2zp/go-wikidata.svg)](https://github.com/Navid2zp/go-wikidata/blob/master/LICENSE) 7 | 8 | 9 | Wikidata API bindings in golang. 10 | 11 | This package is suitable for retrieving data from wikidata database using its public API. 12 | Methods for updating, editing and adding to wikidata are not implemented (yet). 13 | 14 | Read more about wikidata API: https://www.wikidata.org/w/api.php 15 | 16 | ## Contents 17 | 18 | - [Installation](#install) 19 | - [Get Entities](#get-entities) 20 | - [Methods](#get-entity-methods) 21 | - [Get Claims](#get-claims) 22 | - [Methods](#get-claims-methods) 23 | - [Search](#search) 24 | - [Methods](#search-methods) 25 | - [Get Wikipedia Page Item](#get-wikipedia-page-item) 26 | - [Get Available Badges](#get-available-badges) 27 | - [License](#license) 28 | 29 | 30 | ### Install 31 | ``` 32 | go get github.com/Navid2zp/go-wikidata 33 | ``` 34 | 35 | 36 | ### Get Entities 37 | 38 | - Receives a list of entity ids. 39 | - Response will be a pointer to `map[string]Entity` which the key being the entity ID and "Entity" being the data for that entity. 40 | - WikiData action: `wbgetentities` 41 | - WikiData API page: https://www.wikidata.org/w/api.php?action=help&modules=wbgetentities 42 | ```go 43 | // Create a request 44 | req, err := gowikidata.NewGetEntities([]string{"Q1"}) 45 | 46 | // Configurations such as props, sites and etc. 47 | req.SetSites([]string{"enwiki", "fawiki"}) 48 | 49 | // Call get to make the request based on the configurations 50 | res, err := req.Get() 51 | ``` 52 | 53 | ###### Get entity methods: 54 | 55 | Request methods: 56 | 57 | ```go 58 | // Param: props 59 | // Default: info|sitelinks|aliases|labels|descriptions|claims|datatype 60 | req.SetProps([]string{"info", "claims"}) 61 | 62 | // Param: sites 63 | req.SetSites([]string{"enwiki", "fawiki"}) 64 | 65 | // Param: sitefilter 66 | req.SetSiteFilter([]string{"enwiki", "fawiki"}) 67 | 68 | // Param: normalize 69 | req.SetNormalize(true) 70 | 71 | // Param: languagefallback 72 | req.SetLanguageFallback(true) 73 | 74 | // Param: languages 75 | req.SetLanguages([]string{"en", "fa"}) 76 | 77 | // Param: redirects 78 | req.SetRedirects(true) 79 | 80 | // Param: titles 81 | req.SetTitles([]string{"title", "another"}) 82 | 83 | 84 | // Method chaining is also supported 85 | req.SetNormalize(true).SetSites([]string{"enwiki", "fawiki"}) 86 | ``` 87 | 88 | Response methods: 89 | ```go 90 | claimReq, err := res["Q1"].NewGetClaims() 91 | ``` 92 | 93 | Same as calling `NewGetClaims`. See "Get Claims" for more information. 94 | 95 | 96 | ### Get Claims 97 | 98 | - Receives an entity ID or a claim GUID. 99 | - Response will be a pointer to `map[string][]Claim` which the key being the entity ID and value being a list of claims for that entity. 100 | - WikiData action: `wbgetclaims` 101 | - WikiData API page: https://www.wikidata.org/w/api.php?action=help&modules=wbgetclaims 102 | 103 | ```go 104 | // Create a request 105 | // You must either provide entity id or a claim GUID 106 | req, err := gowikidata.NewGetClaims("Q1", "") 107 | 108 | // Call get to make the request based on the configurations 109 | res, err := req.Get() 110 | ``` 111 | 112 | You can also call `NewGetClaims` on `Entity` type. 113 | 114 | ###### Get claims methods: 115 | 116 | Request methods: 117 | 118 | ```go 119 | // Param: props 120 | // Default: references 121 | req.SetProps([]string{"references"}) 122 | 123 | // Param: rank 124 | // One of the following values: deprecated, normal, preferred 125 | req.SetRank("normal") 126 | 127 | // Param: property 128 | req.SetProperty("P31") 129 | ``` 130 | 131 | ### Search 132 | 133 | - Receives search string and search language string. 134 | - Response will be a pointer to `SearchEntitiesResponse` type containing the result as `SearchEntitiesResponse.SearchResult`. 135 | - WikiData action: `wbsearchentities` 136 | - WikiData API page: https://www.wikidata.org/w/api.php?action=help&modules=wbsearchentities 137 | 138 | ```go 139 | // Create a request 140 | // Both search and language are required 141 | req, err := gowikidata.NewSearch("abc", "en") 142 | 143 | // Call get to make the request based on the configurations 144 | res, err := req.Get() 145 | ``` 146 | 147 | ###### Search methods: 148 | 149 | Request methods: 150 | 151 | ```go 152 | // Param: props 153 | // Default: url 154 | req.SetProps([]string{"url"}) 155 | 156 | // Param: limit 157 | // Default: 7 158 | req.SetLimit(10) 159 | 160 | // Param: strictlanguage 161 | req.SetStrictLanguage(true) 162 | 163 | // Param: type 164 | // One of the following values: item, property, lexeme, form, sense 165 | // Default: item 166 | req.SetType("item") 167 | 168 | // Param: continue 169 | // Default: 0 170 | req.SetContinue(7) 171 | ``` 172 | 173 | Response methods: 174 | ```go 175 | // Next page of results 176 | // new coninue = limit + previous continue value 177 | nextPage, err := res.Next() 178 | ``` 179 | 180 | ### Get Wikipedia Page Item 181 | 182 | Find Wikipedia page item ID in wikidata by page slug (https://en.wikipedia.org/wiki/[SLUG]). 183 | 184 | ```go 185 | wikiDataID, err := gowikidata.GetPageItem("Earth") 186 | fmt.Println(wikiDataID) // "Q2" 187 | ``` 188 | 189 | 190 | 191 | ### Get Available Badges 192 | 193 | - Returns a pointer to a list of strings. 194 | - WikiData action: `wbavailablebadges` 195 | - WikiData API page: https://www.wikidata.org/w/api.php?action=help&modules=wbavailablebadges 196 | 197 | ```go 198 | badges, err := gowikidata.GetAvailableBadges() 199 | ``` 200 | 201 | License 202 | ---- 203 | 204 | MIT 205 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Navid2zp/go-wikidata 2 | 3 | go 1.16 4 | 5 | require github.com/Navid2zp/easyreq v1.1.0 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Navid2zp/easyreq v1.1.0 h1:l72URNUdG7u2bsEwc+I/XvlIqHyK1wQh45zlJVfglOs= 2 | github.com/Navid2zp/easyreq v1.1.0/go.mod h1:mXy1+Mp8NBc3ujieKS27RS84REq138ZCvtpj8hFUeYk= 3 | -------------------------------------------------------------------------------- /gowikidata.go: -------------------------------------------------------------------------------- 1 | package gowikidata 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strconv" 7 | 8 | "github.com/Navid2zp/easyreq" 9 | ) 10 | 11 | var ( 12 | WikipediaDomain = "https://en.wikipedia.org" 13 | WikidataDomain = "https://www.wikidata.org" 14 | ImageResizerDomain = "https://commons.wikimedia.org" 15 | ) 16 | 17 | const ( 18 | wikipediaQueryURL = "%s/w/api.php?action=query&prop=pageprops&titles=%s&format=json" 19 | wikiDataAPIURL = "%s/w/api.php?action=%s&format=json" 20 | imageResizerURL = "%s/w/thumb.php?width=%d&f=%s" 21 | ) 22 | 23 | // GetPageItem returns Wikipedia page item ID 24 | func GetPageItem(slug string) (string, error) { 25 | url := fmt.Sprintf(wikipediaQueryURL, WikipediaDomain, slug) 26 | 27 | wikipediaQuery := WikiPediaQuery{} 28 | res, err := easyreq.Make("get", url, nil, "", "json", &wikipediaQuery, nil) 29 | if err != nil { 30 | return "", err 31 | } 32 | 33 | if res.StatusCode() != 200 { 34 | return "", fmt.Errorf("request failed with status code %d", res.StatusCode()) 35 | } 36 | 37 | item := "" 38 | // Get the first item 39 | for _, value := range wikipediaQuery.Query.Pages { 40 | item = value.PageProps.WikiBaseItem 41 | break 42 | } 43 | return item, nil 44 | } 45 | 46 | // NewGetEntities creates and returns a new WikiDataGetEntitiesRequest 47 | // Use this function to initialize a request. 48 | // It will return a pointer to WikiDataGetEntitiesRequest. 49 | // You can make configurations on response. 50 | func NewGetEntities(ids []string) (*WikiDataGetEntitiesRequest, error) { 51 | if len(ids) < 1 { 52 | return nil, errors.New("no ids provided") 53 | } 54 | 55 | req := WikiDataGetEntitiesRequest{ 56 | URL: fmt.Sprintf(wikiDataAPIURL, WikidataDomain, "wbgetentities"), 57 | } 58 | req.setParam("ids", &ids) 59 | return &req, nil 60 | } 61 | 62 | // SetSites sets sites parameter for entities request 63 | func (r *WikiDataGetEntitiesRequest) SetSites(sites []string) *WikiDataGetEntitiesRequest { 64 | r.setParam("sites", &sites) 65 | return r 66 | } 67 | 68 | // SetTitles sets titles parameter for entities request 69 | func (r *WikiDataGetEntitiesRequest) SetTitles(titles []string) *WikiDataGetEntitiesRequest { 70 | r.setParam("titles", &titles) 71 | return r 72 | } 73 | 74 | // SetRedirects sets redirects parameter for entities request 75 | func (r *WikiDataGetEntitiesRequest) SetRedirects(redirect bool) *WikiDataGetEntitiesRequest { 76 | redirectString := "yes" 77 | if !redirect { 78 | redirectString = "no" 79 | } 80 | r.URL += "&redirects=" + redirectString 81 | return r 82 | } 83 | 84 | // SetProps sets props parameter for entities request 85 | // Default: info|sitelinks|aliases|labels|descriptions|claims|datatype 86 | func (r *WikiDataGetEntitiesRequest) SetProps(props []string) *WikiDataGetEntitiesRequest { 87 | r.setParam("props", &props) 88 | return r 89 | } 90 | 91 | // SetLanguages sets languages parameter for entities request 92 | func (r *WikiDataGetEntitiesRequest) SetLanguages(languages []string) *WikiDataGetEntitiesRequest { 93 | r.setParam("languages", &languages) 94 | return r 95 | } 96 | 97 | // SetLanguageFallback sets languagefallback parameter for entities request 98 | func (r *WikiDataGetEntitiesRequest) SetLanguageFallback(fallback bool) *WikiDataGetEntitiesRequest { 99 | if fallback { 100 | r.URL += "&languagefallback=" 101 | } 102 | return r 103 | } 104 | 105 | // SetNormalize sets normalize parameter for entities request 106 | func (r *WikiDataGetEntitiesRequest) SetNormalize(normalize bool) *WikiDataGetEntitiesRequest { 107 | if normalize { 108 | r.URL += "&normalize=" 109 | } 110 | return r 111 | } 112 | 113 | // SetSiteFilter sets sitefilter parameter for entities request 114 | func (r *WikiDataGetEntitiesRequest) SetSiteFilter(sites []string) *WikiDataGetEntitiesRequest { 115 | r.setParam("sitefilter", &sites) 116 | return r 117 | } 118 | 119 | // Get makes a entities request and returns the response or an error 120 | // Call this function after you finished configuring the request. 121 | // It will send the request and unmarshales the response. 122 | func (r *WikiDataGetEntitiesRequest) Get() (*map[string]Entity, error) { 123 | responseData := GetEntitiesResponse{} 124 | res, err := easyreq.Make("GET", r.URL, nil, "", "json", &responseData, nil) 125 | if err != nil { 126 | return nil, err 127 | } 128 | if res.StatusCode() != 200 { 129 | return nil, fmt.Errorf("request failed with status code %d", res.StatusCode()) 130 | } 131 | return &responseData.Entities, nil 132 | } 133 | 134 | // NewGetClaims creates a new claim request for the given entity or claim 135 | // WikiData action: wbgetclaims 136 | // WikiData API page: https://www.wikidata.org/w/api.php?action=help&modules=wbgetclaims 137 | // Either entity or claim must be provided 138 | func NewGetClaims(entity, claim string) (*WikiDataGetClaimsRequest, error) { 139 | if entity == "" && claim == "" { 140 | return nil, errors.New("either entity or claim must be provided") 141 | } 142 | 143 | req := WikiDataGetClaimsRequest{ 144 | URL: fmt.Sprintf(wikiDataAPIURL, WikidataDomain, "wbgetclaims"), 145 | } 146 | if entity != "" { 147 | req.setParam("entity", &[]string{entity}) 148 | } else { 149 | req.setParam("claim", &[]string{claim}) 150 | } 151 | return &req, nil 152 | } 153 | 154 | // NewGetClaims creates a new claim request for an entity 155 | func (e *Entity) NewGetClaims() (*WikiDataGetClaimsRequest, error) { 156 | return NewGetClaims(e.ID, "") 157 | } 158 | 159 | // SetProperty sets property parameter for claims request 160 | func (r *WikiDataGetClaimsRequest) SetProperty(property string) *WikiDataGetClaimsRequest { 161 | r.setParam("property", &[]string{property}) 162 | return r 163 | } 164 | 165 | // SetRank sets rank parameter for claims request 166 | // One of the following values: deprecated, normal, preferred 167 | func (r *WikiDataGetClaimsRequest) SetRank(rank string) *WikiDataGetClaimsRequest { 168 | r.setParam("rank", &[]string{rank}) 169 | return r 170 | } 171 | 172 | // SetProps sets props parameter for claims request 173 | // Default: references 174 | func (r *WikiDataGetClaimsRequest) SetProps(props []string) *WikiDataGetClaimsRequest { 175 | r.setParam("props", &props) 176 | return r 177 | } 178 | 179 | // Get creates a new request for claims and returns the response or an error 180 | func (r *WikiDataGetClaimsRequest) Get() (*map[string][]Claim, error) { 181 | responseData := GetClaimsResponse{} 182 | res, err := easyreq.Make("GET", r.URL, nil, "", "json", &responseData, nil) 183 | if err != nil { 184 | return nil, err 185 | } 186 | if res.StatusCode() != 200 { 187 | return nil, fmt.Errorf("request failed with status code %d", res.StatusCode()) 188 | } 189 | return &responseData.Claims, nil 190 | } 191 | 192 | // GetAvailableBadges returns a pointer to a list of strings. 193 | // WikiData action: wbavailablebadges 194 | // WikiData API page: https://www.wikidata.org/w/api.php?action=help&modules=wbavailablebadges 195 | func GetAvailableBadges() ([]string, error) { 196 | var data struct{ Badges []string } 197 | url := fmt.Sprintf(wikiDataAPIURL, WikidataDomain, "wbavailablebadges") 198 | res, err := easyreq.Make("GET", url, nil, "", "json", &data, nil) 199 | if err != nil { 200 | return nil, err 201 | } 202 | if res.StatusCode() != 200 { 203 | return nil, fmt.Errorf("request failed with status code %d", res.StatusCode()) 204 | } 205 | return data.Badges, nil 206 | } 207 | 208 | // NewSearch creates a new request for entities search and returns response or an error 209 | // Create a request 210 | // Both search and language are required 211 | // WikiData action: wbsearchentities 212 | // WikiData API page: https://www.wikidata.org/w/api.php?action=help&modules=wbsearchentities 213 | func NewSearch(search, language string) (*WikiDataSearchEntitiesRequest, error) { 214 | req := WikiDataSearchEntitiesRequest{ 215 | URL: fmt.Sprintf(wikiDataAPIURL, WikidataDomain, "wbsearchentities"), 216 | Language: language, 217 | // default api value 218 | Limit: 7, 219 | } 220 | req.setParam("search", &[]string{search}) 221 | req.setParam("language", &[]string{language}) 222 | return &req, nil 223 | } 224 | 225 | // SetLimit sets limit parameter 226 | // Default: 7 227 | func (r *WikiDataSearchEntitiesRequest) SetLimit(limit int) *WikiDataSearchEntitiesRequest { 228 | r.Limit = limit 229 | r.setParam("limit", &[]string{strconv.Itoa(limit)}) 230 | return r 231 | } 232 | 233 | // SetStrictLanguage sets strictlanguage parameter 234 | func (r *WikiDataSearchEntitiesRequest) SetStrictLanguage(strictLanguage bool) *WikiDataSearchEntitiesRequest { 235 | if strictLanguage { 236 | r.URL += "&strictlanguage=" 237 | } 238 | return r 239 | } 240 | 241 | // SetType sets type parameter 242 | // One of the following values: item, property, lexeme, form, sense 243 | // Default: item 244 | func (r *WikiDataSearchEntitiesRequest) SetType(t string) *WikiDataSearchEntitiesRequest { 245 | r.setParam("type", &[]string{t}) 246 | return r 247 | } 248 | 249 | // SetProps sets props parameter 250 | // Default: url 251 | func (r *WikiDataSearchEntitiesRequest) SetProps(props []string) *WikiDataSearchEntitiesRequest { 252 | r.setParam("props", &props) 253 | return r 254 | } 255 | 256 | // SetContinue sets continue parameter 257 | // Default: 0 258 | func (r *WikiDataSearchEntitiesRequest) SetContinue(c int) *WikiDataSearchEntitiesRequest { 259 | r.setParam("continue", &[]string{strconv.Itoa(c)}) 260 | return r 261 | } 262 | 263 | // Get makes a entity search request and returns the response or an error 264 | func (r *WikiDataSearchEntitiesRequest) Get() (*SearchEntitiesResponse, error) { 265 | responseData := SearchEntitiesResponse{} 266 | res, err := easyreq.Make("GET", r.URL, nil, "", "json", &responseData, nil) 267 | if err != nil { 268 | return nil, err 269 | } 270 | if res.StatusCode() != 200 { 271 | return nil, fmt.Errorf("request failed with status code %d", res.StatusCode()) 272 | } 273 | 274 | responseData.SearchRequest = *r 275 | return &responseData, nil 276 | } 277 | 278 | // Next page of results for search 279 | // Will use the same configurations as previous request 280 | func (r *SearchEntitiesResponse) Next() (*SearchEntitiesResponse, error) { 281 | res, err := NewSearch(r.SearchRequest.Search, r.SearchRequest.Language) 282 | if err != nil { 283 | return nil, err 284 | } 285 | if r.SearchRequest.Limit > 0 { 286 | res.SetLimit(r.SearchRequest.Limit) 287 | } 288 | if r.SearchRequest.Type != "" { 289 | res.SetType(r.SearchRequest.Type) 290 | } 291 | if len(r.SearchRequest.Props) > 0 { 292 | res.SetProps(r.SearchRequest.Props) 293 | } 294 | if r.SearchRequest.StrictLanguage { 295 | res.SetStrictLanguage(true) 296 | } 297 | 298 | res.SetContinue(r.CurrentContinue + r.SearchRequest.Limit) 299 | response, err := res.Get() 300 | return response, err 301 | } 302 | 303 | // ImageResizer returns the url for resizing a wikimedia image to the given size 304 | func ImageResizer(imageName string, size int) string { 305 | return fmt.Sprintf(imageResizerURL, ImageResizerDomain, size, imageName) 306 | } 307 | 308 | func createParam(param string, values []string) string { 309 | newString := "&" + param + "=" 310 | valuesLen := len(values) 311 | for i, value := range values { 312 | newString += value 313 | if i+1 < valuesLen { 314 | newString += "|" 315 | } 316 | } 317 | return newString 318 | } 319 | -------------------------------------------------------------------------------- /gowikidata_test.go: -------------------------------------------------------------------------------- 1 | package gowikidata 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestNewGetEntities(t *testing.T) { 8 | req, _ := NewGetEntities([]string{"Q1"}) 9 | req.SetSites([]string{"enwiki", "fawiki"}).SetNormalize(true) 10 | 11 | entities, err := req.Get() 12 | if err != nil { 13 | t.Fatalf("entity request faild: %s", err.Error()) 14 | } 15 | 16 | for _, entity := range *entities { 17 | _, err = entity.NewGetClaims() 18 | } 19 | 20 | if err != nil { 21 | t.Fatalf("claim request for entity faild: %s", err.Error()) 22 | } 23 | 24 | } 25 | 26 | func TestGetAvailableBadges(t *testing.T) { 27 | _, err := GetAvailableBadges() 28 | 29 | if err != nil { 30 | t.Fatalf("get badges request faild: %s", err.Error()) 31 | } 32 | } 33 | 34 | func TestNewGetClaims(t *testing.T) { 35 | req, _ := NewGetClaims("Q1", "") 36 | 37 | _, err := req.Get() 38 | if err != nil { 39 | t.Fatalf("claim request faild: %s", err.Error()) 40 | } 41 | } 42 | 43 | func TestNewSearch(t *testing.T) { 44 | req, _ := NewSearch("universe", "en") 45 | 46 | _, err := req.Get() 47 | if err != nil { 48 | t.Fatalf("claim request faild: %s", err.Error()) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /models.go: -------------------------------------------------------------------------------- 1 | package gowikidata 2 | 3 | import ( 4 | "encoding/json" 5 | "strconv" 6 | ) 7 | 8 | // WikiDataGetEntitiesRequest stores entities request url 9 | type WikiDataGetEntitiesRequest struct { 10 | URL string 11 | } 12 | 13 | func (r *WikiDataGetEntitiesRequest) setParam(param string, values *[]string) { 14 | r.URL += createParam(param, *values) 15 | } 16 | 17 | // WikiDataGetClaimsRequest stores claims request url 18 | type WikiDataGetClaimsRequest struct { 19 | URL string 20 | } 21 | 22 | func (r *WikiDataGetClaimsRequest) setParam(param string, values *[]string) { 23 | r.URL += createParam(param, *values) 24 | } 25 | 26 | // WikiDataSearchEntitiesRequest stores parameters for entities search 27 | type WikiDataSearchEntitiesRequest struct { 28 | URL string 29 | Limit int 30 | Language string 31 | Type string 32 | Props []string 33 | StrictLanguage bool 34 | Search string 35 | } 36 | 37 | func (r *WikiDataSearchEntitiesRequest) setParam(param string, values *[]string) { 38 | r.URL += createParam(param, *values) 39 | } 40 | 41 | // Entity represents wikidata entities data 42 | type Entity struct { 43 | ID string `json:"id"` 44 | PageID int `json:"pageid"` 45 | NS int `json:"ns"` 46 | Title string `json:"title"` 47 | LastRevID int `json:"lastrevid"` 48 | Modified string `json:"modified"` 49 | Type string `json:"type"` 50 | Labels map[string]Label `json:"labels"` 51 | Descriptions map[string]Description `json:"descriptions"` 52 | Aliases map[string][]Alias `json:"aliases"` 53 | Claims map[string][]Claim `json:"claims"` 54 | SiteLinks map[string]SiteLink `json:"sitelinks"` 55 | } 56 | 57 | // GetDescription returns entity description in the given language code 58 | func (e *Entity) GetDescription(languageCode string) string { 59 | return e.Descriptions[languageCode].Value 60 | } 61 | 62 | // GetLabel returns entity label in the given language code 63 | func (e *Entity) GetLabel(languageCode string) string { 64 | return e.Labels[languageCode].Value 65 | } 66 | 67 | // Label represents wikidata labels data 68 | type Label struct { 69 | Language string `json:"language"` 70 | Value string `json:"value"` 71 | ForLanguage string `json:"for-language"` 72 | } 73 | 74 | // Description represents wikidata descriptions data 75 | type Description struct { 76 | Language string `json:"language"` 77 | Value string `json:"value"` 78 | ForLanguage string `json:"for-language"` 79 | } 80 | 81 | // Alias represents wikidata aliases data 82 | type Alias struct { 83 | Language string `json:"language"` 84 | Value string `json:"value"` 85 | } 86 | 87 | // SiteLink represents wikidata site links data 88 | type SiteLink struct { 89 | Site string `json:"site"` 90 | Title string `json:"title"` 91 | Badges []string `json:"badges"` 92 | URL string `json:"url"` 93 | } 94 | 95 | // Claim represents wikidata claims data 96 | type Claim struct { 97 | ID string `json:"id"` 98 | Rank string `json:"rank"` 99 | Type string `json:"type"` 100 | MainSnak Snak `json:"mainsnak"` 101 | Qualifiers map[string][]Snak `json:"qualifiers"` 102 | QualifiersOrder []string `json:"qualifiers-order"` 103 | } 104 | 105 | // Snak represents wikidata snak values 106 | type Snak struct { 107 | SnakType string `json:"snaktype"` 108 | Property string `json:"property"` 109 | Hash string `json:"hash"` 110 | DataType string `json:"datatype"` 111 | DataValue DataValue `json:"datavalue"` 112 | } 113 | 114 | // DataValue represents wikidata values 115 | // Wikidata values can be either string or number 116 | // It will store the data type so you can work with it accordingly 117 | type DataValue struct { 118 | Type string `json:"type"` 119 | Value DynamicDataValue `json:"value"` 120 | } 121 | 122 | // DynamicDataValue represents wikidata values for DataValue struct 123 | type DynamicDataValue struct { 124 | Data interface{} 125 | S string 126 | I int 127 | ValueFields DataValueFields 128 | Type string 129 | } 130 | 131 | // UnmarshalJSON unmarshales given json result to DynamicDataValue 132 | // It's main job is to find the data type and set the fields accordingly 133 | func (d *DynamicDataValue) UnmarshalJSON(b []byte) (err error) { 134 | s := string(b) 135 | 136 | // If value starts with " and also ends with " 137 | // Then its string 138 | if string(s[0]) == "\"" && string(s[len(s)-1]) == "\"" { 139 | // Remove extra " from both sides of the string. 140 | cleaned := s[1 : len(s)-1] 141 | d.Data = cleaned 142 | d.S = cleaned 143 | d.Type = "String" 144 | } else { 145 | // If its int 146 | i, err := strconv.Atoi(s) 147 | if err != nil { 148 | // If its not int or string 149 | // Use DataValueFields 150 | values := DataValueFields{} 151 | err := json.Unmarshal(b, &values) 152 | if err != nil { 153 | return err 154 | } 155 | d.Type = "DataValueFields" 156 | d.ValueFields = values 157 | d.Data = values 158 | } else { 159 | // set value 160 | d.Type = "Int" 161 | d.I = i 162 | d.Data = i 163 | } 164 | } 165 | return 166 | } 167 | 168 | // DataValueFields represents wikidata value fields 169 | type DataValueFields struct { 170 | EntityType string `json:"entity-type"` 171 | NumericID int `json:"numeric-id"` 172 | ID string `json:"id"` 173 | Type string `json:"type"` 174 | Value string `json:"value"` 175 | Time string `json:"time"` 176 | Precision float64 `json:"precision"` 177 | Before int `json:"before"` 178 | After int `json:"after"` 179 | TimeZone int `json:"timezone"` 180 | CalendarModel string `json:"calendarmodel"` 181 | Latitude float64 `json:"latitude"` 182 | Longitude float64 `json:"longitude"` 183 | Globe string `json:"globe"` 184 | Amount string `json:"amount"` 185 | LowerBound string `json:"lowerbound"` 186 | UpperBound string `json:"upperbound"` 187 | Unit string `json:"unit"` 188 | Text string `json:"text"` 189 | Language string `json:"language"` 190 | } 191 | 192 | // Reference represents wikidata references 193 | type Reference struct { 194 | Hash string `json:"hash"` 195 | Snaks map[string][]Snak `json:"snaks"` 196 | SnaksOrder []string `json:"snaks-order"` 197 | } 198 | 199 | // GetEntitiesResponse represents wikidata entities response 200 | type GetEntitiesResponse struct { 201 | Entities map[string]Entity `json:"entities"` 202 | Success uint `json:"success"` 203 | } 204 | 205 | // GetClaimsResponse represents wikidata claims response 206 | type GetClaimsResponse struct { 207 | Claims map[string][]Claim `json:"claims"` 208 | } 209 | 210 | // SearchEntity represents wikidata entities search 211 | type SearchEntity struct { 212 | Repository string `json:"repository"` 213 | ID string `json:"id"` 214 | ConceptURI string `json:"concepturi"` 215 | Title string `json:"title"` 216 | PageID int `json:"pageid"` 217 | URL string `json:"url"` 218 | Label string `json:"label"` 219 | Description string `json:"description"` 220 | Match SearchMatch `json:"match"` 221 | DataType string `json:"datatype"` 222 | } 223 | 224 | // SearchMatch represents wikidata search match value 225 | type SearchMatch struct { 226 | Type string `json:"type"` 227 | Language string `json:"language"` 228 | Text string `json:"text"` 229 | } 230 | 231 | // SearchInfo represents wikidata search info 232 | type SearchInfo struct { 233 | Search string `json:"search"` 234 | } 235 | 236 | // SearchEntitiesResponse represents wikidata entities search response 237 | type SearchEntitiesResponse struct { 238 | SearchInfo SearchInfo `json:"searchinfo"` 239 | SearchResult []SearchEntity `json:"search"` 240 | SearchContinue int `json:"search-continue"` 241 | Success uint `json:"success"` 242 | CurrentContinue int 243 | SearchRequest WikiDataSearchEntitiesRequest 244 | } 245 | 246 | // WikiPediaQuery represents wikipedia query 247 | type WikiPediaQuery struct { 248 | BatchComplete string `json:"batchcomplete"` 249 | Query struct { 250 | Pages map[string]struct { 251 | PageProps struct { 252 | WikiBaseItem string `json:"wikibase_item"` 253 | } `json:"pageprops"` 254 | } `json:"pages"` 255 | } `json:"query"` 256 | } 257 | --------------------------------------------------------------------------------