Project Summary:
Business Objective:
To pull automatically generated student email addresses from our MS SQL data warehouse and push into production PowerSchool instances in multiple states.
What I Built:
A ruby script that connects to our data warehouse using an ActiveRecord adapter for SQL server, dynamically queries student records, and converts them into the expected format with a custom JSON serializer. Then it uses Faraday HTTP client to make a call to the PowerSchool API (one per instance in CA and TN) to request a token for authentication. Once authenticated, it sends the JSON request body to the API and returns a response set of success/error messages which are logged locally. The program is integrated into our SSIS integration job server using a nice little PowerShell script to dynamically call the ruby script for each state’s data.
TL;DR: Wrote a ruby script that syncs 15,000+ student emails between a data warehouse and production PowerSchool servers in mutliple states on a daily basis.
Made With:
- Ruby
- PowerSchool API
- MS SQL
- Stored procedure
- Custom views
- PowerShell
- SSIS
Code Samples:
Select methods from the API class demonstrating how the program connects to the PowerSchool API and updates student emails.
# @oauth is a class variable that stores the configuration file secrets
# not exposed here for obvious reasons
private
def connect
# open HTTP connection
Faraday.new(:url => @oauth['url'],:ssl => {:verify => false}) do |faraday|
.request :url_encoded # form-encode POST params
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
faradayend
end
private
def access_token
= connect.post do |request|
result .url "/oauth/access_token"
request.params['client_id'] = @oauth['id']
request.params['client_secret'] = @oauth['secret']
request.params['grant_type'] = 'client_credentials'
requestend
# return token from JSON result
JSON.parse(result.body)['access_token']
end
public
def update_student_emails(body) # takes JSON as the body param
# POST request body of student emails to PowerSchool API
= connect.post do |request|
result .url "/ws/v1/student"
request.options.timeout = 3000 # open/read timeout in seconds
request.options.open_timeout = 10 # connection open timeout in seconds
request.headers['Accept'] = 'application/json'
request.headers['Content-Type'] = 'application/json'
request.headers['Authorization'] = "Bearer #{access_token}"
request.body = body
requestend
# Return human readable JSON result
= JSON.parse(result.body)
parsed = JSON.pretty_generate(parsed)
pretty end
Ruby method for seralizing student emails from SQL to JSON. The PowerSchool Student API expects JSON in a non standard JSON format. That is why custom serialization is needed.
See PowerSchool API Documentation under “Update Students > Request Body Example”
def self.serialize_student_emails(state)
# client_uid is the PowerSchool ID and id is the DCID
= []
studentArray 'production')
connect(= sanitize_sql_array(
query ["SELECT * FROM dbo.StudentEmails WHERE State = ?", state]
).select_all(query).each do |record|
connection<< {
studentArray 'client_uid' => record['client_uid'],
'action' => 'UPDATE',
'id' => record['id'],
'contact_info' => {'email': record['email']}
}
end
= {'students' => {'student' => studentArray}}
studentHash
# return as JSON body
.to_json
studentHashend
PowerShell script: ssms_job.ps1
# This is run from an SSMS job task step
$erroractionpreference = "Stop"
try {
Set-Location 'C:\powerSchoolApi\app'
# Ruby executable location called from Rails Installer
$RUBY = 'C:\RailsInstaller\Ruby2.2.0\bin\ruby.exe'
& $RUBY 'application.rb'
}
catch {
throw 'The application encountered an error. See logs for further explanation.'
exit 1
}