Shortening the REST Endpoint URL Length

I’m using the OAuth process to create an REST Endpoint and then recreating the URL that will be used by a device to directly access the endpoint.

So the URL looks like this

http://graph.api.smartthings.com/api/token/${state.accessToken}/smartapps/installations/${app.id}/Test

The problem is that with the accessToken and app.id the URL is too long for the device to use. The device has a limitation for 128 characters for the URL.

Is there anyway to shorten this URL?

@Ben throwing this at you since you’ve written a lot about REST endpoints

1 Like

No way to shorten the URL. You could try to use a goog.gl URL or something like that… But I doubt that will work. I’d be interested to know if it does.

Seems really restricitve to limit a api to 128 characters… Maybe talk to the device manufacture and see if they can be a little less restricitve?

1 Like

I’ve sent them a note (Foscam) but I HIGHLY doubt they’re going to change it.

I think ST should find an alternative way to deal with device restrictions, couldn’t this be shortened internally by reducing the path size and using smaller tokens? Why not something like

http://api.smartthings.com/${state.accessToken}/${app.id}/Test

If the token is made a little smaller, this is TOTALLY doable!

1 Like

or even

http://api.smartthings.com/${state.accessToken}/Test

Why even need app.id? the token is unique to an app - everything else looks redundant to me.

2 Likes

anyone comments? filler

Considering RFC7230 calls for much longer urls to be used, the issue isn’t with ST shrinking URLs its getting whatever isn’t complying with the RFC standard to comply.

However, if you get closer to 2000 characters or 8000 octets then you might be reaching a practical limit for browsers to process.

Guess you could always write a proxy / relay to get around the device limitation. But it seems odd to make ST change how they handle url length just to support a device that doesn’t comply with the RFC standard.

@pstuart - I agree I didn’t say the issue was with ST, all I said was you’re going to have manufacturers do things which aren’t always compliant, there where software flexibility comes in.

So again the pretty fundamental question - why is there so much redundancy in the ST URL. if the access token is a unique number, why even have the rest?

Maybe for future use. Not everything that might use OAUTH are going to be smartapps. Need the flexibility for future use.

Tokens are not supposed to be forever and this does not follow restful conventions. You would have to filter a url like this:

http://api.smartthings.com/%variable%

Is variable an app id or a token or some other as yet undefined thing?

Well I’m asking ST if they can give an option for a shorter URL to work with devices who’s manufacturers aren’t compliant with specs :smile:

Have you sent in the request to support? Doubt ranting here does much to get a feature added.

1 Like

:smiley: good point! Will do so. I thought ST folks on the forum took requests and support was more for “tech” issues.

LOL, ST folks take requests on the forums. That’s a good one. Unless it has probably 100+ tickets in the support system, I doubt it will even get considered.

1 Like

Okay in the meanwhile if folks need to shorten the URL they can use the following stub.

You will need to sign up for an API KEY here Tiny-URL and replace the apikey XXX with your own key. (just enter your eMail and you’re done!)

also you need to add the following after your preferences section (otherwise the JSON parsing will not work)

groovy.json.JsonSlurper

private String shortenURL(longURL) {
    def params = [
        uri: 'http://tiny-url.info/api/v1/create',
        contentType: 'application/json',
        query: [apikey:'XXX', provider: 'go_ly', format: 'json', url: longURL]
    ]
	
    try {
        httpGet(params) { response ->
			//log.trace "Request was successful, data=$response.data, status=$response.status"
            if (response.data.state == "ok") {
            	log.debug "Short URL: ${response.data.shorturl}"
                log.trace "Long URL: ${response.data.longurl}"
                return response.data.shorturl
            } else {
            	log.error "Error in return short URL: ${response.data}"
            }
        }
    } catch (e) {
        log.error "Error getting shortened URL: $e"
    }
}
1 Like

Just to be clear while this code is perfectly functional the strategy doesn’t always work. Here’s why (after spending a ton of time trying to figure this one out)

There is a delay between the translation of the shortened URL to the full URL once the device/app with the shortened URL hits the website (e.g. tinyURL), however the device/app may not wait until the communication is completed (it has a timeout which doesn’t take into account the translation time). Often the device/smartapp will close the connection BEFORE the translation is complete and because the connection is closed it doesn’t redirect to the new website with the translated HTTP response to redirect.

So if the device doesn’t redirect to the website this strategy is useless!

Hence back to my original request PLEASE consider providing a shorter URL option with REST endpoints!
Thanks

1 Like

There appears to be more that that happening, it appears that ST is also calling events out of order.

So the device first send a alarm on and motion active event to the smart app. A split second later it sends an alarm off and motion inactive events to the app (the app is subscribed to these events)

So the SmartApp should first process the alarm on/motion active events and then process the alarm off (it not subscribed to motion inactive) event, but according to the logs (yes timestamp compensated and more importantly observing other event like lights) it doing it in the reverse order. First it processes the alarm off event followed by the motion active event.

@Ben any thoughts on this one? Is there some behavior of the platform/smartapp I’m not understanding?

I’m also seeing a race condition here but harder to tell because of the timestamp resolution/ordering issue. Is there a way to use locks?

In the alarm off event I remove the device from the list where as in the motion on I first check if the device is in the list before taking some actions. However due to apparent race condition it removes it a split second after the check is done (which appears to be called in the wrong order like pointed out above, but that aside). Hereby if I can lock the entire code until it completes it would avoid this issue. (barring the out of order events which needs to investigated)

The nature of the appEngine ST uses is ASYNC communications, there is no such thing in this ecosystem for pause / lock and wait for response.

Things can and will happen out of order. You have to handle this in the code for the callbacks when the parsing happens.

Plus throw in any packet loss or latency / interference, and it will happen as well.

This isn’t an if a then b, if c then d. A and C can get executed in any order and the result of one doesn’t wait for the other.

However, the IDE should be reporting timestamps in order, but I can understand it just a parsing issue when sending from DB to IDE.

Is there any way to use locks or synchronize two methods? (ie one cannot be called until the other finishes)?

I tried to use @Synchronized(‘state’) on the methods since state is the only global object available and the IDE threw me 2 pages full of errors :)))

Any ideas?

1 Like

Okay I’m going to answer my own question here (it’s kinda out of place in this thread though)

use synchronized with state within the function like:

import groovy.transform.Synchronized

synchronized(state) {
   ...
}
1 Like