JSON API - in GO


(Jenny Adams) #1

Hello Everyone, I am attempting to receive a response from an Rakuten API. Not sure what I am missing because I am getting this response:

{ “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”}

Code -
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))

}

---------------------------side note - this is the guide for the parameters from Rakuten API site

Configure your application or favorite Web Service client (e.g. Advanced Rest Client) to
make the following request:
a. URL: https://api.rakutenmarketing.com/token
b. HTTP Verb: POST
c. Headers:
i. Authorization:
d. Payload:
i. grant_type=password
ii. username=
iii. password=
iv. scope=

------------------------Any Help\assistance\lead would be much appereciated (:

Jenny


(Norbert Melzer) #2

The instructions you posted tell you to use a POST request, you are issuing a GET. Perhaps your problem is related to using the wrong verb?


(Jenny Adams) #3

Hi Norbert,
Thanks for the reply.
Changing the method from GET to POST yields the same result…


(Johan Dahl) #4

I got a little bit further by doing like this. Putting the payload as formdata in the requestbody

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))

}

(Jenny Adams) #5

[Johan Dahl,

Thanks! that gets the connection,(token is refreshed every hour, so that needs to update - the authorization part, probably why you were not able to test) but I am looking for sending the first two types SearchParams and SearchRequest and receiving ItemInfo and Price as a response through print.

Best Regards,


(Jenny Adams) #6

Hi Everyone, Still stuck on this question… not sure how to POST type SearchParams type SearchRequest as input and the rest as output to the API… getting full access and receiving approval token but can’t seem to send the structs to the same address… :frowning:


(Jenny Adams) #7

–Update - I am now using this additional code:
u := SearchParams{Keywords: “Donna”}
t := new(bytes.Buffer)
json.NewEncoder(t).Encode(u)
res, err := http.NewRequest(“POST”, “https://api.rakutenmarketing.com/token”, t)
res.Header.Add(“Authorization”, "Basicdjl6eUp5YUNZX2tZODdOaFRhSmVOZnFqME93YTpGZzJxWHRhNTlvXzUyZ0VNNDFiVThaZjhQa3Nh")
res.Header.Add(“Content-Type”, “application/x-www-form-urlencoded”)
resp1, err := client.Do(res)
if err != nil {
fmt.Print(err.Error())
os.Exit(1)

But I am getting : 500 Internal Server Error.


(Johan Dahl) #8

Now is the content json so try changing:

res.Header.Add(“Content-Type”, “application/x-www-form-urlencoded”)

to

res.Header.Add(“Content-Type”, “application/json”)

And also do you have an example from the documentation how the request should look in json? Now it sends:

{"keywords":"Donna"}

(Jenny Adams) #9

According to documentation the struct needs to look like this: of course there are other structs, but once I am able to send one it is much simpler.

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"`

(Johan Dahl) #10

SearchParams is that a name you come up with yourself or should it be part of the json? like this:

{"SearchParams": { "keywords": ..., ...}}

or should the json be:

{ "keywords": ..., ...}

Is the documentation secret or can you share that part?


(Jenny Adams) #11

SearchParams is something I use. I am sending the documentation for the API I am looking for. Thanks for your help (:slight_smile:


(Johan Dahl) #12

Hi thanks for the PDF. But then I look into that it seems that all searches are made by using GET wih all parameters in the question part like the example from the pdf

https://api.rakutenmarketing.com/productsearch/1.0?keyword=beverage
&sort=retailprice&sorttype=asc&sort=productname&sorttype=asc

The easiest way of constructing this with som flexibility would be like this


	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))


(Jenny Adams) #13

Hi , thank you very much for the feedback and council.

I’ll explain the GET/POST confusion…It makes sense what you say and code indeed runs but returns a 403 error. I think that the issue is that the refresh token is misisng from the first request.

{ “fault”: { “code”: “403”, “type”: “Status report”, “message”: “Runtime Error”, “description”: “No matching resource found in the API
for the given request” } }

As can be seen from this PDF : https://ufile.io/dxzwq
which states how to acquire the first token(beginning of our conversation - we have that running), the refresh token is needed in the payload to make additional requests but the initial request is in POST.

Any idea?
Once again, thank you very much!


(Johan Dahl) #14

Hi

By reading the two pdf:s you provided I think something like this should work. But I can’t test it. The result should be in xml-format. Maybe you could below change req.Header.Add(“Accept”, “application/xml”) to req.Header.Add(“Accept”, “application/json”) and get json instead. I wish you god luck with this.

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() {
	// This is step #4 (page 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)
	}

	// It should result in a bearer token
	var bt bearerToken
	err = json.NewDecoder(resp.Body).Decode(&bt)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(bt)

	// The most important i think is the access_token which is used for all other searches

	/* Here is a sample request for the first page (pagenumber=1) of 20 results
	(max=20) related to Dog Collar (keyword=” Dog Collar”) in the Pets category
	(cat=”Pets”) for English language from the Advertiser associated with 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))

}