module Jamf::Connection::ClassicAPI

This module defines methods used for interacting with the Classic API. This includes creating the Faraday connection, sending HTTP requests and handling responses

Public Instance Methods

c_delete(rsrc) click to toggle source

Delete a resource from the Classic API

@param rsrc the resource to create, the URL part after ‘JSSResource/’

@return [String] the xml response from the server.

    # File lib/jamf/api/connection/classic_api.rb
162 def c_delete(rsrc)
163   validate_connected
164   raise MissingDataError, 'Missing :rsrc' if rsrc.nil?
165 
166   rsrc = rsrc.delete_prefix Jamf::Connection::SLASH
167 
168   # delete the resource
169   resp =
170     @c_cnx.delete(rsrc) do |req|
171       req.headers[Jamf::Connection::HTTP_CONTENT_TYPE_HEADER] = Jamf::Connection::MIME_XML
172       req.headers[Jamf::Connection::HTTP_ACCEPT_HEADER] = Jamf::Connection::MIME_XML
173     end
174   @last_http_response = resp
175 
176   unless resp.success?
177     handle_classic_http_error resp
178     return
179   end
180 
181   resp.body
182 end
Also aliased as: delete_rsrc
c_get(rsrc, format = :json, raw_json: false) click to toggle source

Get a Classic API resource via GET

The first argument is the resource to get (the part of the API url after the ‘JSSResource/’ ) The resource must be properly URL escaped beforehand. Note: URL.encode is deprecated, use CGI.escape

By default we get the data in JSON, and parse it into a ruby Hash with symbolized Hash keys.

If the second parameter is :xml then the XML version is retrieved and returned as a String.

To get the raw JSON string as it comes from the API, pass raw_json: true

@param rsrc the resource to get

(the part of the API url after the 'JSSResource/' )

@param format either ;json or :xml

If the second argument is :xml, the XML data is returned as a String.

@param raw_json When GETting JSON, return the raw unparsed string

(the XML is always returned as a raw string)

@return [Hash,String] the result of the get

   # File lib/jamf/api/connection/classic_api.rb
61 def c_get(rsrc, format = :json, raw_json: false)
62   rsrc = rsrc.delete_prefix Jamf::Connection::SLASH
63 
64   validate_connected
65   raise Jamf::InvalidDataError, 'format must be :json or :xml' unless Jamf::Connection::GET_FORMATS.include?(format)
66 
67   resp =
68     @c_cnx.get(rsrc) do |req|
69       req.headers[Jamf::Connection::HTTP_ACCEPT_HEADER] = format == :json ? Jamf::Connection::MIME_JSON : Jamf::Connection::MIME_XML
70       # puts "Classic API Cookie is: #{req.headers['Cookie']}"
71     end
72   @last_http_response = resp
73   unless resp.success?
74     handle_classic_http_error resp
75     return
76   end
77 
78   return JSON.parse(resp.body, symbolize_names: true) if format == :json && !raw_json
79 
80   # the raw body, either json or xml
81   resp.body
82 end
Also aliased as: get_rsrc
c_post(rsrc, xml) click to toggle source

Create a new Classic API resource via POST

@param rsrc the API resource being created, the URL part after ‘JSSResource/’

@param xml the xml specifying the new object.

@return [String] the xml response from the server.

    # File lib/jamf/api/connection/classic_api.rb
 94 def c_post(rsrc, xml)
 95   validate_connected
 96 
 97   rsrc = rsrc.delete_prefix Jamf::Connection::SLASH
 98 
 99   # convert CRs & to 
100   xml&.gsub!(/\r/, '
')
101 
102   # send the data
103   resp =
104     @c_cnx.post(rsrc) do |req|
105       req.headers[Jamf::Connection::HTTP_CONTENT_TYPE_HEADER] = Jamf::Connection::MIME_XML
106       req.headers[Jamf::Connection::HTTP_ACCEPT_HEADER] = Jamf::Connection::MIME_XML
107       req.body = xml
108     end
109   @last_http_response = resp
110 
111   unless resp.success?
112     handle_classic_http_error resp
113     return
114   end
115 
116   resp.body
117 end
Also aliased as: post_rsrc
c_put(rsrc, xml) click to toggle source

Update an existing Classic API resource

@param rsrc the API resource being changed, the URL part after ‘JSSResource/’

@param xml the xml specifying the changes.

@return [String] the xml response from the server.

    # File lib/jamf/api/connection/classic_api.rb
129 def c_put(rsrc, xml)
130   validate_connected
131 
132   rsrc = rsrc.delete_prefix Jamf::Connection::SLASH
133 
134   # convert CRs & to 
135   xml.gsub!(/\r/, '
')
136 
137   # send the data
138   resp =
139     @c_cnx.put(rsrc) do |req|
140       req.headers[Jamf::Connection::HTTP_CONTENT_TYPE_HEADER] = Jamf::Connection::MIME_XML
141       req.headers[Jamf::Connection::HTTP_ACCEPT_HEADER] = Jamf::Connection::MIME_XML
142       req.body = xml
143     end
144   @last_http_response = resp
145 
146   unless resp.success?
147     handle_classic_http_error resp
148     return
149   end
150 
151   resp.body
152 end
Also aliased as: put_rsrc
delete_rsrc(rsrc)

backward compatibility

Alias for: c_delete
get_rsrc(rsrc, format = :json, raw_json: false)

backward compatibility

Alias for: c_get
post_rsrc(rsrc, xml)

backward compatibility

Alias for: c_post
put_rsrc(rsrc, xml)

backward compatibility

Alias for: c_put
upload(rsrc, local_file) click to toggle source

Upload a file. This is really only used for the ‘fileuploads’ endpoint of the classic API, as implemented in the Uploadable mixin module, q.v.

@param rsrc the API resource being uploadad-to,

the URL part after 'JSSResource/'

@param local_file[String, Pathname] the local file to upload

@return [String] the xml response from the server.

    # File lib/jamf/api/connection/classic_api.rb
197 def upload(rsrc, local_file)
198   validate_connected
199   rsrc = rsrc.delete_prefix Jamf::Connection::SLASH
200 
201   payload = {}
202   payload[:name] = Faraday::Multipart::FilePart.new(local_file.to_s, 'application/octet-stream')
203 
204   resp = @c_cnx.post rsrc, payload
205 
206   @last_http_response = resp
207 
208   unless resp.success?
209     handle_classic_http_error resp
210     return false
211   end
212 
213   true
214 end

Private Instance Methods

create_classic_connection() click to toggle source

create the faraday CAPI connection object

    # File lib/jamf/api/connection/classic_api.rb
220 def create_classic_connection
221   Faraday.new(@c_base_url, ssl: ssl_options) do |cnx|
222     # use a proc for the token value, so its looked up on every request
223     # meaning we don't have to validate that the token is still valid before every request
224     # because the Token instance will (usually) refresh it automatically.
225     cnx.request :authorization, 'Bearer', -> { @token.token }
226 
227     cnx.options[:timeout] = @timeout
228     cnx.options[:open_timeout] = @open_timeout
229 
230     cnx.request :multipart
231     cnx.request :url_encoded
232 
233     cnx.adapter :net_http
234   end
235 end
handle_classic_http_error(resp) click to toggle source

Parses the given http response and raises a Jamf::APIError with a useful error message.

@return [void]

    # File lib/jamf/api/connection/classic_api.rb
242 def handle_classic_http_error(resp)
243   return if resp.success?
244 
245   case resp.status
246   when 404
247     err = Jamf::NoSuchItemError
248     msg = 'Not Found'
249   when 409
250     err = Jamf::ConflictError
251 
252     # TODO: Clean this up
253     resp.body =~ /<p>(The server has not .*?)(<|$)/m
254     msg = Regexp.last_match(1)
255 
256     unless msg
257       resp.body =~ %r{<p>Error: (.*?)</p>}
258       msg = Regexp.last_match(1)
259     end
260 
261     unless msg
262       resp.body =~ /<p>(Unable to complete file upload.*?)(<|$)/m
263       msg = Regexp.last_match(1)
264     end
265   when 400
266     err = Jamf::BadRequestError
267     resp.body =~ %r{>Bad Request</p>\n<p>(.*?)</p>\n<p>You can get technical detail}m
268     msg = Regexp.last_match(1)
269   when 401
270     if resp.body.include? 'INVALID_TOKEN'
271       err = Jamf::InvalidConnectionError
272       msg = 'Connection token is not valid'
273     else
274       err = Jamf::AuthorizationError
275       msg = 'You are not authorized to do that.'
276     end
277   when (500..599)
278     err = Jamf::APIRequestError
279     msg = 'There was an internal server error'
280   else
281     err = Jamf::APIRequestError
282     msg = "There was a error processing your request, status: #{resp.status}"
283   end
284   raise err, msg
285 end