My goal is to address "lost update problem" (see http://www.w3.org/1999/04/Editing/) in PUT operations.
I am using sinatra, and as a client I use rest_client. How I can check if it works? My client always return 200 code. Am I using arguments of calling it correctly? (PUT itself works)
sinatra code:
put '/players/:id' do |id|
etag 'something'
if Player[id].nil? then
halt 404
end
begin
data = JSON.parse(params[:data])
pl = Player[id]
pl.name = data['name']
pl.position = data['position']
if pl.save
"Resource modified."
else
status 412
redirect '/players'
end
rescue Sequel::DatabaseError
409 #Conflict - The request was unsuccessful due to a conflict in the state of the resource.
rescue Exception => e
400
puts e.message
end
end
client invocation:
player = {"name" => "John Smith", "position" => "def"}.to_json
RestClient.put('http://localhost:4567/players/1', {:data => player, :content_type => :json, :if_none_match => '"something"'}){ |response, request, result, &block|
p response.code.to_s + " " + response
}
I tried already to put :if_none_match => "something", I tried :if_match. Nothing changes.
How I can put headers into RestClient request?
How to obtain sth different than 200 status? (ie 304 not modified)?
Your payload and headers are in the same hash. You have to specify the headers for RestClient in second hash. Try:
player = {"name" => "John Smith", "position" => "def"}.to_json
headers = {:content_type => :json, :if_none_match => '"something"'}
RestClient.put('http://localhost:4567/players/1', {:data => player}, headers) do |response, request, result, &block|
p response.code.to_s + " " + response
end
I am not sure if RestClient translates the headers correctly. If the above doesn't work, try it with:
headers = {'Content-Type' => :json, 'If-None-Match' => '"something"'}
Related
I want to change Yahoo ads conversion tracker name through API automatically.
But, when I run the following code, that returned an error.
access_token = XXXXXXXXXXXXX
account_id = XXXXXX
conversion_id = XXXXXXX
new_name = "new_name"
header = {"Content-Type": "application/json",\
"Accept": "application/json",\
"Authorization": "Bearer " + access_token}
url = "https://ads-search.yahooapis.jp/api/v8/ConversionTrackerService/set"
data = {'accountId':account_id, 'operand':[{'accountId': account_id, 'conversionTrackerId': conversion_id, "conversionTrackerName": new_name}]}
data = json.dumps(data).encode()
req = urllib.request.Request(url, data=data, method='POST', headers=header)
try:
with urllib.request.urlopen(req) as response:
body = json.loads(response.read())
headers = response.getheaders()
status = response.getcode()
print(headers)
print(status)
print(body)
except urllib.error.URLError as e:
print(e.reason)`
Retuened error is:
{'errors': [{'code': 'L0001', 'message': 'Lower list size.', 'details': [{'requestKey': 'operand', 'requestValue': None}]}], 'rid': '6fab0e1ac60dd2a871831484791976bf', 'rval': None}
I guess the length of "operand" field is 1 and it is right length according to yahoo api document. What I shuold do to fix this error?
I tryied to make length of "operand" field 2. But the result was same.
I am building a scala application. Within the application, we are making a call to an external service, and fetching the data.
When I am hitting the endpoint of this external service using the
postman, I am getting the complete data, around 9000 lines of JSON
data, within 9 seconds.
But when I am hitting the same endpoint through my scala application, I am getting a 200 OK response, but getting the below error:
[WARN] [06/09/2022 18:05:45.765] [default-akka.actor.default-dispatcher-9] [default/Pool(shared->http://ad-manager-api-production.ap-south-1.elasticbeanstalk.com:80)] [4 (WaitingForResponseEntitySubscription)] Response entity was not subscribed after 100 seconds. Make sure to read the response entity body or call `discardBytes()` on it. GET /admin/campaigns Empty -> 200 OK Chunked
I read about it and found that we can set response-entity-subscription-timeout property to a higher value. I set it to about 100 seconds, but this does not seem to help.
My Code:
private val sendAndReceive = customSendAndReceive.getOrElse(HttpClientUtils.singleRequest)
.
.
.
def getActiveCampaigns: GetActiveCampaigns = () => {
val request = HttpRequest(
uri = s"$endpoint/admin/campaigns?status=PUBLISHED", // includes both PUBLISHED_READY and PUBLISHED_PAUSED
method = HttpMethods.GET,
headers = heathers
)
sendAndReceive(request).timed(getActiveCampaignsTimer).flatMap {
case HttpResponse(StatusCodes.OK, _, entity, _) =>
Unmarshal(entity).to[List[CampaignListDetailsDto]]
case response#HttpResponse(_, _, _, _) =>
response.discardEntityBytes()
Future.failed(new RuntimeException(s"Ad manager service exception: $response"))
case response =>
log.error(s"Error calling ad manager service: $response")
response.discardEntityBytes()
Future.failed(new RuntimeException(s"Ad manager service exception: $response"))
}
}
.
.
.
def getCampaignSpendData(getActiveCampaigns: GetActiveCampaigns, getCampaignTotalSpend: GetCampaignTotalSpend)(implicit ec: ExecutionContext): GetCampaignsSpendData = () => {
getActiveCampaigns()
.andThen {
case Failure(t) => log.error("Failed to fetch ads from ad manager", t)
}
.flatMap {
campaignList => Future.sequence(campaignList.map(campaign => budgetSpendPercentage(getCampaignTotalSpend)(campaign)))
}
}
Questions
What does this error exactly mean? Is it that it is able to connect to the endpoint but not able to get the complete data from it before the connection is closed/reset?
How can we address this issue?
I' am using groovy to consume a POST Rest api : here is my code :
import groovyx.net.http.RESTClient
#Grab (group = 'org.codehaus.groovy.modules.http-builder', module = 'http-builder', version = '0.7.1')
def url = "https://poc-ser.tst.be/"
def client = new RESTClient(url)
client.ignoreSSLIssues()
client.auth.basic(login,pswd)
client.post(
path: "osidoc/api/rest/production/documents?id=46",
contentType:'application/json',
headers: [Accept: 'application/json' , Authorization: 'Authorization']
)
But I always get error " error groovyx.net.http.ResponseParseException: OK caused by: groovy.json.JsonException: Unable to determine the current character, " Knowing that the response should be "application/msword" type (i.e : the response should be a word doc)
EDIT
I tried to change the Accept to "application/octet-stream' but it showed me an other error "406Invalid Accept header. Only XML and JSON are supported.`"
No matter what value I enter as my request's "Content-Type", the outgoing request I send out seems to replace it with "application/x-www-form-urlencoded". The application I'm trying to hit expects "application/json". My code, basically, is below.
{-# LANGUAGE OverloadedStrings #-}
import Network.Wreq
...
submissionResources = ["https://widgets.example.com/v2/widgets/request"]
sendWidgetToEndpoint submissionResources workingToken key widgetArray = do
let opts = defaults & header "Content-Type" .~ ["application/json"]
& header "apikey" .~ [key]
& header "Authorization" .~ [workingToken]
endPointURL = head submissionResources
widgetId = widgetArray !! 0
numberOfWidgets = widgetArray !! 1
widgetText = widgetArray !! 2
submissionResult <- postWith opts endPointURL [ "widgetId" := widgetId
, "numWidgets" := numberOfWidgets
, "widgetText" := widgetText
]
return submissionResult
My problem is that I keep getting back Status {statusCode = 415, statusMessage = "Unsupported Media Type"} from this endpoint, and I'm confident this is because the request I'm sending appears to be overriding "Content-Type" in my header. I have tried using "application/json" and "text/plain" but the response I get back always indicates to me that all the headers I sent over look as expected except for Content-Type which invariably has become "application/x-www-form-urlencoded".
How can I ensure wreq keeps 'Content-Type: application/json' in my requests header?
EDIT: I'm determining what headers were in my original request by what the API server tells me in its response back to me.
The type of the last argument to postWith in your snippet is [FormParam], and that type is what forces the Content-Type to be urlencoded.
To send JSON, send something of type Value or Encoding (from Data.Aeson).
import Data.Aeson (pairs, (.=))
...
-- also remove the "Content-Type" field from opts
submissionResult <- postWith opts endpointURL $ pairs
( "widgetId" .= widgetId <>
"numWidgets" .= numberOfWidgets <>
"widgetText" .= widgetText )
...
The Content-Type is set by the payload you pass to postWith, via the Postable instance. If you want to use yet another Content-Type header, define your own type with a Postable instance where you set an appropriate Content-Type. You can also choose to not set any Content-Type in the Postable instance, so you can set it via the options instead.
I need to create a Groovy post build script in Jenkins and I need to make a request without using any 3rd party libraries as those can't be referenced from Jenkins.
I tried something like this:
def connection = new URL( "https://query.yahooapis.com/v1/public/yql?q=" +
URLEncoder.encode(
"select wind from weather.forecast where woeid in " + "(select woeid from geo.places(1) where text='chicago, il')",
'UTF-8' ) )
.openConnection() as HttpURLConnection
// set some headers
connection.setRequestProperty( 'User-Agent', 'groovy-2.4.4' )
connection.setRequestProperty( 'Accept', 'application/json' )
// get the response code - automatically sends the request
println connection.responseCode + ": " + connection.inputStream.text
but I also need to pass a JSON in the POST request and I'm not sure how I can do that. Any suggestion appreciated.
Executing POST request is pretty similar to a GET one, for example:
import groovy.json.JsonSlurper
// POST example
try {
def body = '{"id": 120}'
def http = new URL("http://localhost:8080/your/target/url").openConnection() as HttpURLConnection
http.setRequestMethod('POST')
http.setDoOutput(true)
http.setRequestProperty("Accept", 'application/json')
http.setRequestProperty("Content-Type", 'application/json')
http.outputStream.write(body.getBytes("UTF-8"))
http.connect()
def response = [:]
if (http.responseCode == 200) {
response = new JsonSlurper().parseText(http.inputStream.getText('UTF-8'))
} else {
response = new JsonSlurper().parseText(http.errorStream.getText('UTF-8'))
}
println "response: ${response}"
} catch (Exception e) {
// handle exception, e.g. Host unreachable, timeout etc.
}
There are two main differences comparing to GET request example:
You have to set HTTP method to POST
http.setRequestMethod('POST')
You write your POST body to outputStream:
http.outputStream.write(body.getBytes("UTF-8"))
where body might be a JSON represented as string:
def body = '{"id": 120}'
Eventually it's good practice to check what HTTP status code returned: in case of e.g. HTTP 200 OK you will get your response from inputStream while in case of any error like 404, 500 etc. you will get your error response body from errorStream.