REST Integration Patterns for ServiceNow
ServiceNow provides RESTMessageV2 for outbound REST API calls and the REST API for inbound requests.
Outbound REST (Calling External APIs)
Basic GET Request
var request = new sn_ws.RESTMessageV2() request.setEndpoint("https://api.example.com/users") request.setHttpMethod("GET") request.setRequestHeader("Accept", "application/json")
var response = request.execute() var httpStatus = response.getStatusCode() var body = response.getBody()
if (httpStatus == 200) { var data = JSON.parse(body) gs.info("Found " + data.length + " users") }
POST Request with JSON Body
var request = new sn_ws.RESTMessageV2() request.setEndpoint("https://api.example.com/incidents") request.setHttpMethod("POST") request.setRequestHeader("Content-Type", "application/json") request.setRequestHeader("Accept", "application/json")
var payload = { title: "New Incident", description: "Created from ServiceNow", priority: "high", } request.setRequestBody(JSON.stringify(payload))
var response = request.execute()
Using REST Message Records
Create a REST Message record for reusable integrations:
// Using predefined REST Message from sys_rest_message var request = new sn_ws.RESTMessageV2("External API", "Create User")
// Set variable substitutions defined in the REST Message request.setStringParameter("user_name", userName) request.setStringParameter("email", email)
var response = request.execute()
Authentication Methods
Basic Authentication
var request = new sn_ws.RESTMessageV2() request.setEndpoint("https://api.example.com/data") request.setHttpMethod("GET") request.setBasicAuth("username", "password")
Bearer Token
var request = new sn_ws.RESTMessageV2() request.setEndpoint("https://api.example.com/data") request.setHttpMethod("GET") request.setRequestHeader("Authorization", "Bearer " + token)
OAuth 2.0 (Using OAuth Profile)
var request = new sn_ws.RESTMessageV2() request.setEndpoint("https://api.example.com/data") request.setHttpMethod("GET") request.setAuthenticationProfile("oauth2", "My OAuth Profile")
API Key
var request = new sn_ws.RESTMessageV2() request.setEndpoint("https://api.example.com/data") request.setHttpMethod("GET") request.setRequestHeader("X-API-Key", apiKey) // Or as query parameter request.setQueryParameter("api_key", apiKey)
Error Handling
try { var request = new sn_ws.RESTMessageV2() request.setEndpoint("https://api.example.com/data") request.setHttpMethod("GET") request.setHttpTimeout(10000) // 10 second timeout
var response = request.execute() var httpStatus = response.getStatusCode()
if (httpStatus == 200) { var body = response.getBody() var data = JSON.parse(body) // Process successful response } else if (httpStatus == 401) { gs.error("Authentication failed") } else if (httpStatus == 404) { gs.error("Resource not found") } else if (httpStatus >= 500) { gs.error("Server error: " + httpStatus) } else { gs.error("Unexpected status: " + httpStatus) } } catch (ex) { gs.error("REST Exception: " + ex.message) }
Response Handling
Parse JSON Response
var body = response.getBody() var data = JSON.parse(body)
// Access nested data var userName = data.user.name var items = data.items || []
Handle Arrays
var body = response.getBody() var users = JSON.parse(body)
for (var i = 0; i < users.length; i++) { var user = users[i] gs.info("User: " + user.name + " (" + user.email + ")") }
Response Headers
var contentType = response.getHeader("Content-Type") var rateLimitRemaining = response.getHeader("X-RateLimit-Remaining")
MCP Tools for REST
// Create REST Message record snow_create_rest_message({ name: "External API", endpoint: "https://api.example.com", authentication: "basic", // or "oauth2", "api_key" methods: [ { name: "Get Users", http_method: "GET", endpoint: "/users", }, { name: "Create User", http_method: "POST", endpoint: "/users", content_type: "application/json", }, ], })
// Test REST connection snow_test_rest_connection({ endpoint: "https://api.example.com/health", })
Best Practices
-
Use REST Message records - Centralized configuration, easier maintenance
-
Set timeouts - Prevent hanging scripts with setHttpTimeout()
-
Handle all status codes - Not just 200
-
Log failures - Use gs.error() for debugging
-
Use Async for slow APIs - Don't block business rules
-
Store credentials securely - Use Connection & Credential Aliases
-
Implement retry logic - For transient failures
-
Rate limit awareness - Check response headers, implement backoff
Retry Pattern
function callApiWithRetry(endpoint, maxRetries) { var retries = 0 var delay = 1000 // Start with 1 second
while (retries < maxRetries) { try { var request = new sn_ws.RESTMessageV2() request.setEndpoint(endpoint) request.setHttpMethod("GET")
var response = request.execute()
if (response.getStatusCode() == 200) {
return JSON.parse(response.getBody())
}
if (response.getStatusCode() >= 500) {
// Server error - retry
retries++
gs.sleep(delay)
delay = delay * 2 // Exponential backoff
continue
}
// Client error - don't retry
throw new Error("Client error: " + response.getStatusCode())
} catch (ex) {
retries++
if (retries >= maxRetries) {
throw ex
}
gs.sleep(delay)
delay = delay * 2
}
} }