1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Cocoaの機能を使ってURLをGET/POSTするAppleScriptハンドラ

Last updated at Posted at 2018-07-21

URLをGETするAppleScriptハンドラ

  • シェルでいうところのcurl 'http://www.example.com/'みたいなもの
GETRequestForURL.scpt
use scripting additions
use framework "Foundation"

set requestURL to current application's NSURL's URLWithString:"https://www.example.com/"

set response to my GETRequestForURL(requestURL)

set returnedString to current application's NSString's alloc()'s initWithData:(response's |data|) encoding:(current application's NSUTF8StringEncoding)
return returnedString as text

on GETRequestForURL(requestURL)
	--require framework: Foundation
	set session to my getValidURLSession()
	set task to session's dataTaskWithURL:requestURL
	task's resume()
	return my fetchURLSesstionTasksResult(current application's NSArray's arrayWithObject:task)'s firstObject()
end GETRequestForURL

on getValidURLSession()
	--require framework: Foundation
	global URLSession
	try
		if URLSession = missing value then
			error number -2753
		end if
	on error number -2753
		set configuration to current application's NSURLSessionConfiguration's ephemeralSessionConfiguration()
		set URLSession to current application's NSURLSession's sessionWithConfiguration:configuration delegate:(me) delegateQueue:(missing value)
	end try
	return URLSession
end getValidURLSession

on URLSession:session didBecomeInvalidWithError:anError
	global URLSession
	log "URLSession invalidated"
	set URLSession to missing value
end URLSession:didBecomeInvalidWithError:

on fetchURLSesstionTasksResult(tasks)
	my waitForCompletionOfURLSessionTasks(tasks)
	my errorURLSessionTasksIfNeeded(tasks)
	return my getResponsesToURLSessionTasks(tasks)
end fetchURLSesstionTasksResult

on waitForCompletionOfURLSessionTasks(tasks)
	--require framework: Foundation
	set tasksAreRunningPredicate to current application's NSPredicate's predicateWithFormat_("NONE state == %@", current application's NSURLSessionTaskStateRunning as integer)
	repeat until tasksAreRunningPredicate's evaluateWithObject:tasks
		delay 0.01
	end repeat
end waitForCompletionOfURLSessionTasks

on errorURLSessionTasksIfNeeded(tasks)
	--require framework: Foundation
	repeat with errorTask in (tasks's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:"error != nil"))
		error errorTask's |error|'s localizedDescription as text number errorTask's |error|'s code as integer
	end repeat
	repeat with notCompletedTask in (tasks's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat_("state != %@", current application's NSURLSessionTaskStateCompleted as integer)))
		error "task has not completed"
	end repeat
end errorURLSessionTasksIfNeeded

on getResponsesToURLSessionTasks(tasks)
	--require framework: Foundation
	global responsesToURLSessionTask
	try
		responsesToURLSessionTask
	on error number -2753
		set responsesToURLSessionTask to current application's NSMutableArray's alloc()'s init()
	end try
	set newTasksFilterPredicate to current application's NSPredicate's predicateWithFormat_("NOT (taskIdentifier IN %@)", responsesToURLSessionTask's valueForKeyPath:"task.taskIdentifier")
	repeat with newTask in (tasks's filteredArrayUsingPredicate:newTasksFilterPredicate)
		(responsesToURLSessionTask's addObject:{task:newTask, |data|:current application's NSMutableData's alloc()'s init()})
	end repeat
	responsesToURLSessionTask's sortUsingDescriptors:{current application's NSSortDescriptor's sortDescriptorWithKey:"task.taskIdentifier" ascending:true}
	set responsesFilterPredicate to current application's NSPredicate's predicateWithFormat_("task.taskIdentifier IN %@", tasks's valueForKey:"taskIdentifier")
	return responsesToURLSessionTask's filteredArrayUsingPredicate:responsesFilterPredicate
end getResponsesToURLSessionTasks

on getResponseToURLSesstionTask(task)
	--require framework: Foundation
	return my getResponsesToURLSessionTasks(current application's NSArray's arrayWithObject:task)'s firstObject()
end getResponseToURLSesstionTask

on URLSession:session taskIsWaitingForConnectivity:task
	log "waiting for connectivity..."
end URLSession:taskIsWaitingForConnectivity:

on URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend
	log "sending..."
end URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:

on URLSession:session dataTask:task didReceiveData:aData
	log "receiving..."
	set receivedData to my getResponseToURLSesstionTask(task)'s |data|
	receivedData's appendData:aData
end URLSession:dataTask:didReceiveData:

on URLSession:session task:task didCompleteWithError:anError
	log "URLSessionTask completed"
end URLSession:task:didCompleteWithError:

URLをPOSTするAppleScriptハンドラ

  • シェルでいうところのcurl -F 'name=value' 'http://www.example.com/'みたいなもの
POSTRequestForURL.scpt
use scripting additions
use framework "Foundation"

set requestURL to current application's NSURL's URLWithString:"https://www.example.com/"
set postString to current application's NSString's stringWithString:"name=value"
set allowedCharacters to current application's NSCharacterSet's URLQueryAllowedCharacterSet
set postData to (postString's stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters)'s dataUsingEncoding:(current application's NSUTF8StringEncoding)

set response to my POSTRequestForURL(requestURL, postData)

set returnedString to current application's NSString's alloc()'s initWithData:(response's |data|) encoding:(current application's NSUTF8StringEncoding)
return returnedString as text

on POSTRequestForURL(requestURL, dataToPost)
	--require framework: Foundation
	set request to current application's NSMutableURLRequest's requestWithURL:requestURL
	set request's HTTPMethod to "POST"
	request's setValue:"application/x-www-form-urlencoded" forHTTPHeaderField:"Content-Type"
	set session to my getValidURLSession()
	set task to session's uploadTaskWithRequest:request fromData:dataToPost
	task's resume()
	return my fetchURLSesstionTasksResult(current application's NSArray's arrayWithObject:task)'s firstObject()
end POSTRequestForURL

on getValidURLSession()
	--require framework: Foundation
	global URLSession
	try
		if URLSession = missing value then
			error number -2753
		end if
	on error number -2753
		set configuration to current application's NSURLSessionConfiguration's ephemeralSessionConfiguration()
		set URLSession to current application's NSURLSession's sessionWithConfiguration:configuration delegate:(me) delegateQueue:(missing value)
	end try
	return URLSession
end getValidURLSession

on URLSession:session didBecomeInvalidWithError:anError
	global URLSession
	log "URLSession invalidated"
	set URLSession to missing value
end URLSession:didBecomeInvalidWithError:

on fetchURLSesstionTasksResult(tasks)
	my waitForCompletionOfURLSessionTasks(tasks)
	my errorURLSessionTasksIfNeeded(tasks)
	return my getResponsesToURLSessionTasks(tasks)
end fetchURLSesstionTasksResult

on waitForCompletionOfURLSessionTasks(tasks)
	--require framework: Foundation
	set tasksAreRunningPredicate to current application's NSPredicate's predicateWithFormat_("NONE state == %@", current application's NSURLSessionTaskStateRunning as integer)
	repeat until tasksAreRunningPredicate's evaluateWithObject:tasks
		delay 0.01
	end repeat
end waitForCompletionOfURLSessionTasks

on errorURLSessionTasksIfNeeded(tasks)
	--require framework: Foundation
	repeat with errorTask in (tasks's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:"error != nil"))
		error errorTask's |error|'s localizedDescription as text number errorTask's |error|'s code as integer
	end repeat
	repeat with notCompletedTask in (tasks's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat_("state != %@", current application's NSURLSessionTaskStateCompleted as integer)))
		error "task has not completed"
	end repeat
end errorURLSessionTasksIfNeeded

on getResponsesToURLSessionTasks(tasks)
	--require framework: Foundation
	global responsesToURLSessionTask
	try
		responsesToURLSessionTask
	on error number -2753
		set responsesToURLSessionTask to current application's NSMutableArray's alloc()'s init()
	end try
	set newTasksFilterPredicate to current application's NSPredicate's predicateWithFormat_("NOT (taskIdentifier IN %@)", responsesToURLSessionTask's valueForKeyPath:"task.taskIdentifier")
	repeat with newTask in (tasks's filteredArrayUsingPredicate:newTasksFilterPredicate)
		(responsesToURLSessionTask's addObject:{task:newTask, |data|:current application's NSMutableData's alloc()'s init()})
	end repeat
	responsesToURLSessionTask's sortUsingDescriptors:{current application's NSSortDescriptor's sortDescriptorWithKey:"task.taskIdentifier" ascending:true}
	set responsesFilterPredicate to current application's NSPredicate's predicateWithFormat_("task.taskIdentifier IN %@", tasks's valueForKey:"taskIdentifier")
	return responsesToURLSessionTask's filteredArrayUsingPredicate:responsesFilterPredicate
end getResponsesToURLSessionTasks

on getResponseToURLSesstionTask(task)
	--require framework: Foundation
	return my getResponsesToURLSessionTasks(current application's NSArray's arrayWithObject:task)'s firstObject()
end getResponseToURLSesstionTask

on URLSession:session taskIsWaitingForConnectivity:task
	log "waiting for connectivity..."
end URLSession:taskIsWaitingForConnectivity:

on URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend
	log "sending..."
end URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:

on URLSession:session dataTask:task didReceiveData:aData
	log "receiving..."
	set receivedData to my getResponseToURLSesstionTask(task)'s |data|
	receivedData's appendData:aData
end URLSession:dataTask:didReceiveData:

on URLSession:session task:task didCompleteWithError:anError
	log "URLSessionTask completed"
end URLSession:task:didCompleteWithError:

複数のURLを並列でGETするAppleScriptハンドラ

parallelGETRequestForURLs.scpt
use scripting additions
use framework "Foundation"

set requestURLs to {current application's NSURL's URLWithString:"https://www.example.com/", current application's NSURL's URLWithString:"https://www.apple.com", current application's NSURL's URLWithString:"https://www.yahoo.co.jp"}

set responses to my parallelGETRequestForURLs(requestURLs)

repeat with response in responses
	set returnedString to (current application's NSString's alloc()'s initWithData:(response's |data|) encoding:(current application's NSUTF8StringEncoding))
	log returnedString as text
end repeat

on parallelGETRequestForURLs(requestURLs)
	--require framework: Foundation
	set session to my getValidURLSession()
	set tasks to current application's NSMutableArray's alloc()'s init()
	repeat with requestURL in requestURLs
		set task to (session's dataTaskWithURL:requestURL)
		task's resume()
		(tasks's addObject:task)
	end repeat
	return my fetchURLSesstionTasksResult(tasks)
end parallelGETRequestForURLs

on getValidURLSession()
	--require framework: Foundation
	global URLSession
	try
		if URLSession = missing value then
			error number -2753
		end if
	on error number -2753
		set configuration to current application's NSURLSessionConfiguration's ephemeralSessionConfiguration()
		set URLSession to current application's NSURLSession's sessionWithConfiguration:configuration delegate:(me) delegateQueue:(missing value)
	end try
	return URLSession
end getValidURLSession

on URLSession:session didBecomeInvalidWithError:anError
	global URLSession
	log "URLSession invalidated"
	set URLSession to missing value
end URLSession:didBecomeInvalidWithError:

on fetchURLSesstionTasksResult(tasks)
	my waitForCompletionOfURLSessionTasks(tasks)
	my errorURLSessionTasksIfNeeded(tasks)
	return my getResponsesToURLSessionTasks(tasks)
end fetchURLSesstionTasksResult

on waitForCompletionOfURLSessionTasks(tasks)
	--require framework: Foundation
	set tasksAreRunningPredicate to current application's NSPredicate's predicateWithFormat_("NONE state == %@", current application's NSURLSessionTaskStateRunning as integer)
	repeat until tasksAreRunningPredicate's evaluateWithObject:tasks
		delay 0.01
	end repeat
end waitForCompletionOfURLSessionTasks

on errorURLSessionTasksIfNeeded(tasks)
	--require framework: Foundation
	repeat with errorTask in (tasks's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:"error != nil"))
		error errorTask's |error|'s localizedDescription as text number errorTask's |error|'s code as integer
	end repeat
	repeat with notCompletedTask in (tasks's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat_("state != %@", current application's NSURLSessionTaskStateCompleted as integer)))
		error "task has not completed"
	end repeat
end errorURLSessionTasksIfNeeded

on getResponsesToURLSessionTasks(tasks)
	--require framework: Foundation
	global responsesToURLSessionTask
	try
		responsesToURLSessionTask
	on error number -2753
		set responsesToURLSessionTask to current application's NSMutableArray's alloc()'s init()
	end try
	set newTasksFilterPredicate to current application's NSPredicate's predicateWithFormat_("NOT (taskIdentifier IN %@)", responsesToURLSessionTask's valueForKeyPath:"task.taskIdentifier")
	repeat with newTask in (tasks's filteredArrayUsingPredicate:newTasksFilterPredicate)
		(responsesToURLSessionTask's addObject:{task:newTask, |data|:current application's NSMutableData's alloc()'s init()})
	end repeat
	responsesToURLSessionTask's sortUsingDescriptors:{current application's NSSortDescriptor's sortDescriptorWithKey:"task.taskIdentifier" ascending:true}
	set responsesFilterPredicate to current application's NSPredicate's predicateWithFormat_("task.taskIdentifier IN %@", tasks's valueForKey:"taskIdentifier")
	return responsesToURLSessionTask's filteredArrayUsingPredicate:responsesFilterPredicate
end getResponsesToURLSessionTasks

on getResponseToURLSesstionTask(task)
	--require framework: Foundation
	return my getResponsesToURLSessionTasks(current application's NSArray's arrayWithObject:task)'s firstObject()
end getResponseToURLSesstionTask

on URLSession:session taskIsWaitingForConnectivity:task
	log "waiting for connectivity..."
end URLSession:taskIsWaitingForConnectivity:

on URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend
	log "sending..."
end URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:

on URLSession:session dataTask:task didReceiveData:aData
	log "receiving..."
	set receivedData to my getResponseToURLSesstionTask(task)'s |data|
	receivedData's appendData:aData
end URLSession:dataTask:didReceiveData:

on URLSession:session task:task didCompleteWithError:anError
	log "URLSessionTask completed"
end URLSession:task:didCompleteWithError:

更新履歴

  • 2018-07-20: FoundationフレームワークのNSURLSessionクラスを使って作成
  • 2018-07-21: エラー対応機能を追加
  • 2018-08-17: POSTRequestForURLハンドラを作成
  • 2018-08-18: NSURLSessionConfigurationを、キャッシュやcookieを使用しないephemeralSessionConfigurationに変更
  • 2018-09-05: invalidateされたURLSessionを避けるためにgetValidURLSessionハンドラを作成
  • 2018-09-06: getResponsesToURLSessionTasksハンドラを作成して並列実行に対応
  • 2018-09-10: 並列にGETリクエストを実行するparallelGETRequestForURLsハンドラを作成
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?