Get HTTP Status using swift - http

I am sorry, I haven't found an answer for my question(( Please, don't be very harsh, I am not a professional programmer, but I keep learning and hope once I will be able to answer someone's question))
I am trying to get HTTP Status of the link (I am sort of generating links depending on one database entries code, like ABCDEF, I keep them in an array and then generate a link to second database, like www.blablabla.ABCDEF.net), so I can see whether the page exists in database or not.
I have written this code, but something is wrong. So maybe it's a question like: "What's wrong with my code?" But on the stack they also say, you have to show your attempts of problem solving...
I wish I could keep it all swift, without any additional modules or something, I think NSHTTPURLResponse must be enough, but I am using it somehow wrong.
Looking forward to help and replies))
var err: NSError!
NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse?, data: NSData!, error: err) -> Void in
if (err != nil) {
let httpStatus: NSHTTPURLResponse = response as NSHHTPURLResponse
for myLink in allLinks {
println("HERE IS THE CURRENT STATUS CODE" + httpStatus.statusCode + "OF A LINK:" + myLink)
if httpStatus.statusCode == 200 {println("SUCCESS!!!!!")}
}
}
}

The fundamental issue here is that you appear to be looking at the statusCode only if the err is not nil. But if you have error, you probably don't have status code. The error parameter to the closure indicates fundamental network issue that probably prevented you from getting to the page in question. The statusCode is generally only meaningful if the error was nil (i.e. you succeeded in connecting to the server), in which case the statusCode is how the server informs you of its ability to service the HTTP request.
A couple of minor things:
You don't need the var err: NSError! line (because the error object is passed as parameter to the closure). This variable you've declared is not used here.
I don't see how error: err as the third parameter to the closure could have worked. The syntax is "variableName: variableType", but there is no type of err.
Likewise, your code is referring to a non-existent class, NSHHTPURLResponse. In Swift 3 and later, it's HTTPURLResponse.
It's probably prudent to do if let for the retrieval of the HTTPURLResponse in order to get the statusCode.
I'm unclear as to your intent in iterating through allLinks, because this connection is just for a given request, not a bunch of links. Just look at the statusCode in light of the particular request. If you need to test multiple URLs, then you do a separate request for each.
We should consider any codes between 200 and 299 as success, not just 200. I'd suggest using the range 200 ..< 300.
Thus:
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, let httpResponse = response as? HTTPURLResponse, error == nil else {
print("No valid response")
return
}
guard 200 ..< 300 ~= httpResponse.statusCode else {
print("Status code was \(httpResponse.statusCode), but expected 2xx")
return
}
// everything OK, process `data` here
}
task.resume()
I also made a few other changes (updated for Swift 3 and later; use URLSession rather than URLConnection; I think error is fine choice for the variable name; I prefer the trailing closure syntax; I tend to use inferred types for closure parameters to make the declaration a little more concise, etc.), but all of that is immaterial to the question at hand: Hopefully this illustrates how one checks the status code.
For Swift 2 rendition, see previous revision of this answer.

[Swift 5.2]
Hi there, you can try this one:
let task = URLSession.shared.dataTask(with: yourRequest) {
(data, response, error) in
guard let response = response else {
print("Cannot found the response")
return
}
let myResponse = response as! HTTPURLResponse
print("Status Code:", myResponse.statusCode)
}
task.resume()
Here is the output
Status Code: 200
(This is your StatusCode)

Related

Is it a bad idea for a WebAPI to return different types depending on some condition?

I have this code which returns a different type depdending on a condition:
[HttpGet("{questionId:int}/specific")]
public async Task<IActionResult> GetSpecificByQuestionIdAsync(int questionId)
{
IActionResult result = Ok();
try
{
var question = await _questionService.GetQuestionByIdAsync(questionId);
if (question != null)
{
if (question.TypeName == "TypeA")
{
var typeA = await _questionService.GetTypeAQuestionAsync(questionId);
result = Ok(typeA);
}
else if (question.TypeName == "TypeB")
{
var typeB = await _questionService.GetTypeBQuestionAsync(questionId);
result = Ok(typeB);
}
}
}
catch (Exception ex)
{
result = StatusCode(StatusCodes.Status500InternalServerError, ex.Message);
}
return result;
}
I want to ask if this is a bad idea or is this gonna cause some problem. I tried searching but couldn't get any info regarding returning different types for REST APIs. Or is it better to make this just 2 separate calls?
I prefer to do not return diferent types from the same URL. This will make more dificult to consume your API, as you can return diferent types of response body for the same response code (200). But if TypeA and TypeB inhiret from the same base Type and you think that would not be a problem to your consumers to handle the differences from TypeA and TypeB, maybe this should not be a problem.
I have worked with some payment APIs that have a property that has a diferent types based on the payment method used by the user. In this case, was easy to handle because the root object was always the same, just one property could be completely different, and I could known wich kind of cast I nedded to do based on the paymentType property at the root object.
If you look at some API guide lines, you probably will not see anyone saying that is a bad practice. But you will always see that are a pattern at the same url always return the same type of response.
Sametimes this kind of differente results are acceptable, and sometimes are not. To answer your question you should think:
How hard will be to the consumer of this API to handle this diferent objects?
Some good api good practice references are:
https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design
https://oai.github.io/Documentation/start-here.html
One problem that I saw in your code is that you are writting the exception message on your 500 error result. This is a great risk as sometimes the exception message could show potential security risks of your application.

Dart: client.post() method in the http.dart package is hanging and isn't returning a future

I am currently implementing a simple ONVIF client program in dart and am having a bit of trouble with handling futures in the http.dart package.
In my code below, the client.post() method returns a Future<response> (containing body/header/status code and so on...) and in my case I would need to receive this before the if/else statement, hence why I have used await. Trouble is the program just hangs and doesn't proceed past the client.post()line.
I know I might need to do a client.close() somewhere but I've tried lots of different ways and nothing works. Here is my current code with some comments to try and explain it a bit:
// The Variables:
// reqSysDateAndTime is a soap message we are sending to the device.
// onvifDev is just a place where the device details are stored.
// probeMatch is a class that stores important info from the ws-discovery stage.
Future<String> checkXaddrsAndGetTime(Device onvifDev, ProbeMatch probeMatch) async {
// Set up the client and uri.
Uri uri = Uri.parse(probeMatch.xaddrs);
http.Client client = http.Client();
// Send the POST request, with full SOAP envelope as the request body
print('[Setup]: Listening for Date/Time response...');
Response response = await client.post(uri, body: reqSysDateAndTime);
print("${response.body}");
// Determine if the address is usable or not.
if (response != null) {
// Set this address as 'working'
onvifDev.xAddrs = probeMatch.xaddrs;
return response.body;
}
else {
return null; // The address does not work
}
}
I also know that this isn't an issue with the actual body of the request because if I do...
client.post(uri, body: reqSysDateAndTime).then((onValue) => print(onValue.body));
...instead, it will print out the response which I'm expecting.
I understand that this is probably a small fix that I'm missing but any help would be much appreciated.
Cheers.
To briefly answer my own question, turns out it was a silly error on my part where the address I was using was link-local - hence why it was hanging at client.post(). There is a nice method in the InternetAddress class here, amongst some other useful methods, which checks to see if the address is link-local or not.

INDY Error 212 while executing createPairwise

I am trying to execute createPairwise function of indy-sdk package.
It throws an INDY Error 212 => WalletItemNotFound.
(I also executed createAndStoreMyDid function)
Here is my code
let [myDid, myVerkey] = await sdk.createAndStoreMyDid(await indy.wallet.get(), {});
let theirVerkey = await sdk.keyForDid(await indy.pool.get(), await indy.wallet.get(), theirDid);
let meta = JSON.stringify({
theirEndpointDid: theirEndpointDid,
verified: false // Indicates that the owner of the agent has confirmed they want to stay connected with this person.
});
//FIXME: Check to see if pairwise exists
await sdk.createPairwise(await indy.wallet.get(), theirDid, myDid, meta);
Can anybody help me out?
In your code, there's actually 2 places where IndySDK 1.11.1 can throw 212 WalletItemNotFound.
1. The first is on this line:
let theirVerkey = await sdk.keyForDid(await indy.pool.get(), await indy.wallet.get(), theirDid);
IndySDK will first try to see if the DID under variable theirDid is not one of your DIDs, stored in your wallet. If no, it will try to find this DID on the ledger. If it's still not found, it will throw WalletItemNotFound. You can check out this behaviour in the IndySDK Rust code here:
https://github.com/hyperledger/indy-sdk/blob/v1.11.1/libindy/src/commands/did.rs#L331
2. However I assume this is not actually your case and you having this error coming out from
wait sdk.createPairwise(await indy.wallet.get(), theirDid, myDid, meta);
If you look how is this method implemented in Rust
https://github.com/hyperledger/indy-sdk/blob/v1.11.1/libindy/src/commands/pairwise.rs#L84
you will see that it's calling get_indy_record for both theirDid and myDid you've supplied. Hence you can't create pairwise record without having both DIDs stored in wallet first. You can assure your wallet contains theirDid by calling storeTheirDid method. In
sdk.storeTheirDid(wh, {did:'V4SGRU86Z58d6TV7PBUe6f', verkey: 'GJ1SzoWzavQYfNL9XkaJdrQejfztN4XqdsiV4ct3LXKL'} )
After calling this, you will be able to call createPairwise between you and them without an issue.
IndySDK version / caching note
I think you might be using some older version of IndySDK. In IndySDK 1.11.1 when keyForDid resolves something from ledger, it actually caches this data, so the code you've posted actually worked out of the box for me without an error.

Check errors when calling http.ResponseWriter.Write()

Say I have this http handler:
func SomeHandler(w http.ResponseWriter, r *http.Request) {
data := GetSomeData()
_, err := w.Write(data)
}
Should I check the error returned by w.Write? Examples I've seen just ignore it and do nothing. Also, functions like http.Error() do not return an error to be handled.
It's up to you. My advice is that unless the documentation of some method / function explicitly states that it never returns a non-nil error (such as bytes.Buffer.Write()), always check the error and the least you can do is log it, so if an error occurs, it will leave some mark which you can investigate should it become a problem later.
This is also true for writing to http.ResponseWriter.
You might think ResponseWriter.Write() may only return errors if sending the data fails (e.g. connection closed), but that is not true. The concrete type that implements http.ResponseWriter is the unexported http.response type, and if you check the unexported response.write() method, you'll see it might return a non-nil error for a bunch of other reasons.
Reasons why ResponseWriter.Write() may return a non-nil error:
If the connection was hijacked (see http.Hijacker): http.ErrHijacked
If content length was specified, and you attempt to write more than that: http.ErrContentLength
If the HTTP method and / or HTTP status does not allow a response body at all, and you attempt to write more than 0 bytes: http.ErrBodyNotAllowed
If writing data to the actual connection fails.
Even if you can't do anything with the error, logging it may be of great help debugging the error later on. E.g. you (or someone else in the handler chain) hijacked the connection, and you attempt to write to it later; you get an error (http.ErrHijacked), logging it will reveal the cause immediately.
Tip for "easy" logging errors
If you can't do anything with the occasional error and it's not a "showstopper", you may create and use a simple function that does the check and logging, something like this:
func logerr(n int, err error) {
if err != nil {
log.Printf("Write failed: %v", err)
}
}
Using it:
logerr(w.Write(data))
Tip for "auto-logging" errors
If you don't even want to use the logerr() function all the time, you may create a wrapper for http.ResponseWriter which does this "automatically":
type LogWriter struct {
http.ResponseWriter
}
func (w LogWriter) Write(p []byte) (n int, err error) {
n, err = w.ResponseWriter.Write(p)
if err != nil {
log.Printf("Write failed: %v", err)
}
return
}
Using it:
func SomeHandler(w http.ResponseWriter, r *http.Request) {
w = LogWriter{w}
w.Write([]byte("hi"))
}
Using LogWriter as a wrapper around http.ResponseWriter, should writes to the original http.ResponseWriter fail, it will be logged automatically.
This also has the great benefit of not expecting a logger function to be called, so you can pass a value of your LogWriter "down" the chain, and everyone who attempts to write to it will be monitored and logged, they don't have to worry or even know about this.
But care must be taken when passing LogWriter down the chain, as there's also a downside to this: a value of LogWriter will not implement other interfaces the original http.ResponseWriter might also do, e.g. http.Hijacker or http.Pusher.
Here's an example on the Go Playground that shows this in action, and also shows that LogWriter will not implement other interfaces; and also shows a way (using 2 "nested" type assertions) how to still get out what we want from LogWriter (an http.Pusher in the example).
I want to add to #icza solution. You don't need to create logging structure, you can use simple function:
func logWrite(write func([]byte) (int, error), body []byte) {
_, err := write(body)
if err != nil {
log.Printf("Write failed: %v", err)
}
}
Take a look on that approach based on the #icza code: https://play.golang.org/p/PAetVixCgv4

In node.js, how do I get Request Unit Charges from call to DocumentClient.queryDocuments()?

I'm using the queryDocuments() method from the node.js client for the first time. I've previously used readDocument(), executeStoredProcedure(), replaceStoredProcedure(), etc. and all of those return a header object that allows you to inspect the 'x-ms-request-charge' header to discern the request unit charge for the operation. However, when using the queryDocuments() or readDocuments() methods, it returns an QueryIterator and I don't see a way to inspect it to see the RUs for the operation.
I suspect that the reason for this is that it's not one operation. It's a series of operations and you didn't implement a way to aggregate the total RUs for the entire thing. I'm willing to hit the REST API directly to get this myself, but I wanted to ask if there was a way to get it with the current library before I went through the trouble.
You can inspect response headers (e.g. x-ms-request-charge) by inspecting the third input parameter in the callback for queryIterator.executeNext().
For example, here is a code sample that uses the response header (x-ms-retry-after-ms) to implement retry logic on throttles (error 429).
var queryIterator = documentClient.queryDocuments(collection._self, query);
executeNextWithRetry(yourCallback);
function executeNextWithRetry(callback) {
queryIterator.executeNext(function(err, results, responseHeaders) {
if(err && err.code === 429 && responseHeaders['x-ms-retry-after-ms']) {
console.log("Retrying after " + responseHeaders['x-ms-retry-after-ms']);
setTimeout(function() {
executeNextWithRetry(callback);
}, responseHeaders['x-ms-retry-after-ms']);
} else {
callback(err, results, responseHeaders);
}
});
}

Resources