使用Golang构建JSON API的实践指南
使用Golang构建JSON API的实践指南 大家好,我正在尝试从乐天API接收响应。不确定哪里出了问题,因为我收到了这样的响应:
{ "fault": { "code": "403", "type": "Status report", "message": "Runtime Error", "description": "No matching resource found in the API for the given request" }
{"grant_type":"password","password":"jj","scope":342511,"username":"jj"}
代码:
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"encoding/json"
)
type SearchParams struct {
Keywords string `json:"keywords"`
}
type SearchRequest struct {
RegionID string `json:"region"`
UserID string `json:"uid"`
}
//output API response
type ItemInfo struct {
ASIN string `json:"asin,omitempty"`
PartnerID string `json:"pid,omitempty"`
DetailPageURL string `json:"detailPageURL,omitempty"`
}
type Price struct {
CurrencyCode string `json:"currencyCode,omitempty"`
Amount float32 `json:"amount,omitempty"`
}
type PointPrice struct {
AMEX float32 `json:"AMEX,omitempty"`
CUR float32 `json:"CUR,omitempty"`
ThankYou float32 `json:"ThankYou,omitempty"`
Discover float32 `json:"Discover,omitempty"`
}
type ItemListings struct {
ItemList []ItemInfo `json:"items"`
CashLow string `json:"cashlow,omitempty"`
}
func main() {
client := &http.Client{
}
response, err := client.Get("https://api.rakutenmarketing.com/token")
req, err := http.NewRequest("GET", "https://api.rakutenmarketing.com/token", nil)
req.Header.Add("Authorization", `"Basic djl6eUp5YUNZX2tZODdOaFRhSmVOZnFqME93YTpGZzJxWHRhNTlvXzUyZ0VNNDFiVThaZjhQa3Nh"`)
//resp, err := client.Do(req)
if err != nil {
fmt.Print(err.Error())
os.Exit(1)
}
payload := map[string]interface{}{"grant_type": "password","username":"jj","password":"pp1234","scope":342511}
byts, _ := json.Marshal(payload)
fmt.Println(string(byts))
responseData, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatal(err)
}
var responseObject SearchParams
json.Unmarshal(responseData, &responseObject)
fmt.Println(string(responseData))
}
---------------------------附注 - 这是乐天API网站的参数指南
配置您的应用程序或常用的Web服务客户端(例如Advanced Rest Client)以发出以下请求: a. URL:https://api.rakutenmarketing.com/token b. HTTP动词:POST c. 头部: i. 授权: d. 负载: i. grant_type=password ii. username= iii. password= iv. scope=
------------------------任何帮助/协助/线索都将非常感激 (:
更多关于使用Golang构建JSON API的实践指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html
你发布的说明要求使用POST请求,而你发出的是GET请求。或许你的问题与使用了错误的请求方式有关?
更多关于使用Golang构建JSON API的实践指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
诺伯特,你好, 感谢你的回复。 将方法从GET改为POST后结果依然相同……
SearchParams 是您自己起的名字,还是应该作为 json 的一部分?像这样:
{"SearchParams": { "keywords": ..., ...}}
或者 json 应该是:
{ "keywords": ..., ...}
文档是保密的,还是可以分享这部分内容?
感谢!这样就能建立连接了(令牌每小时刷新,所以需要更新授权部分,这可能是您无法测试的原因),但我正在寻找通过打印发送前两种类型 SearchParams 和 SearchRequest,并接收 ItemInfo 和 Price 作为响应。
诚挚问候,
大家好,我仍然卡在这个问题上……不知道如何将 SearchParams 类型的 SearchRequest 作为输入提交到 API,并将其余部分作为输出……虽然获得了完全访问权限并收到了批准令牌,但似乎无法将结构体发送到同一地址…… 
我使用SearchParams。我正在发送我正在寻找的API文档。感谢您的帮助 🙂

Uploadfiles.io - ProductSearch_1.0_May2017.pdf
免费、安全、匿名、无限制地上传文件。@UploadFilesFree
现在内容已经是 JSON 格式了,尝试将:
res.Header.Add(“Content-Type”, “application/x-www-form-urlencoded”)
改为
res.Header.Add(“Content-Type”, “application/json”)
另外,文档中是否有关于请求在 JSON 中应如何呈现的示例?现在它发送的是:
{"keywords":"Donna"}
您好,非常感谢您的反馈和建议。
我会解释一下GET/POST的困惑…您说的很有道理,代码确实能运行但返回403错误。我认为问题在于第一个请求中缺少刷新令牌。
{ "fault": { "code": "403", "type": "Status report", "message": "Runtime Error", "description": "No matching resource found in the API
for the given request" } }
从这份PDF可以看出:https://ufile.io/dxzwq 其中说明了如何获取第一个令牌(我们对话的开始 - 我们已经实现了这部分),在进行额外请求时需要在有效负载中包含刷新令牌,但初始请求是使用POST方法。
有什么想法吗? 再次表示衷心的感谢!
引用 johandalabacka 的回复:
另外,文档中是否有示例说明请求的 JSON 格式应该如何?现在发送的是:
res.Header.Add(“Content-Type”, “application/json”)是的,已经尝试过了。 但返回的是 400 错误请求
根据文档,结构体需要如下定义:当然还有其他结构体,但一旦我能成功发送一个请求,后续就会简单很多。
type SearchParams struct {
Keywords string `json:"keywords"`
SearchIndex string `json:"index"`
Page string `json:"page"`
PriceLow int `json:"price_low"`
PriceHigh int `json:"price_high"`
AwardLow int `json:"award_low"`
AwardHigh int `json:"award_high"`
我通过以下方式取得了一些进展。将有效载荷作为表单数据放入请求体中:
func main() {
v := url.Values{}
v.Add("grant_type", "password")
v.Add("username", "jj")
v.Add("password", "pp1234")
v.Add("scope", "342511")
r := bytes.NewReader([]byte(v.Encode()))
client := &http.Client{}
req, err := http.NewRequest("POST", "https://api.rakutenmarketing.com/token", r)
req.Header.Add("Authorization", `"Basic djl6eUp5YUNZX2tZODdOaFRhSmVOZnFqME93YTpGZzJxWHRhNTlvXzUyZ0VNNDFiVThaZjhQa3Nh"`)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req)
if err != nil {
fmt.Print(err.Error())
os.Exit(1)
}
responseData, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(responseData))
}
感谢您提供的PDF文档。但经过查阅,我发现所有搜索都是通过GET请求实现的,所有参数都放在查询部分,如PDF中的示例所示:
https://api.rakutenmarketing.com/productsearch/1.0?keyword=beverage &sort=retailprice&sorttype=asc&sort=productname&sorttype=asc
最具灵活性的构建方式如下所示:
v.Add("keyword", "beverage")
v.Add("sort", "retailprice")
v.Add("sorttype", "asc")
v.Add("productname", "productname")
v.Add("sorttype", "asc")
url := "https://api.rakutenmarketing.com/productsearch/1.0?" + v.Encode()
fmt.Println(url)
client := &http.Client{}
req, err := http.NewRequest("GET", "https://api.rakutenmarketing.com/token", r)
req.Header.Add("Authorization", `"Basic djl6eUp5YUNZX2tZODdOaFRhSmVOZnFqME93YTpGZzJxWHRhNTlvXzUyZ0VNNDFiVThaZjhQa3Nh"`)
resp, err := client.Do(req)
if err != nil {
fmt.Print(err.Error())
os.Exit(1)
}
responseData, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(responseData))
通过阅读您提供的两份PDF文档,我认为以下代码应该可行。但我无法进行测试。结果应该是XML格式。您或许可以将下面的 req.Header.Add("Accept", "application/xml") 改为 req.Header.Add("Accept", "application/json") 来获取JSON格式的数据。祝您好运。
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
)
type bearerToken struct {
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
AccessToken string `json:"access_token"`
}
func main() {
// 这是步骤 #4(第5页)
v := url.Values{}
v.Add("grant_type", "password")
v.Add("username", "jj")
v.Add("password", "pp1234")
v.Add("scope", "342511")
r := bytes.NewReader([]byte(v.Encode()))
client := &http.Client{}
req, err := http.NewRequest("POST", "https://api.rakutenmarketing.com/token", r)
req.Header.Add("Authorization", `"Basic djl6eUp5YUNZX2tZODdOaFRhSmVOZnFqME93YTpGZzJxWHRhNTlvXzUyZ0VNNDFiVThaZjhQa3Nh"`)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req)
if err != nil {
fmt.Print(err.Error())
os.Exit(1)
}
// 应该会返回一个承载令牌
var bt bearerToken
err = json.NewDecoder(resp.Body).Decode(&bt)
if err != nil {
log.Fatal(err)
}
fmt.Println(bt)
// 我认为最重要的是access_token,它用于所有其他搜索
/* 这是一个示例请求,用于获取与宠物类别中狗项圈相关的第一页(页码=1)20个结果(最大=20),
英语语言,来自ID为2557的广告商(mid=2557):
https://api.rakutenmarketing.com/productsearch/1.0?keyword="Dog collar"
&cat="Pets"&language=en_US&max=20&pagenumber=1&mid=2557*/
v = url.Values{}
v.Add("keyword", "\"Dog Collar\"")
v.Add("cat", "\"Pets\"")
v.Add("language", "en_US")
v.Add("max", "20")
v.Add("pagenumber", "1")
v.Add("mid", "2557")
url := "https://api.rakutenmarketing.com/productsearch/1.0?" + v.Encode()
client = &http.Client{}
req, err = http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer "+bt.AccessToken)
req.Header.Add("Accept", "application/xml")
resp, err = client.Do(req)
if err != nil {
fmt.Print(err.Error())
os.Exit(1)
}
responseData, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(responseData))
}


