The AngularJS $http service is great for most any communication you need to do with the web services that are likely backing your single-page-application. However one place where it doesn’t quite do what you usually want is in the deserialization of dates.

Using $http to post a blog entry for example is pretty easy:

myPost = 
  id: 123
  title: 'Using HTTP Interceptors to Deserialize Dates'
  status: 'draft'
  creationDate: new Date()
  body: 'TBD'
 
$http.post('/api/blog', myPost)

This results in the following JSON being posted to the server:

{
  "id": 123
  "title": "Using HTTP Interceptors to Deserialize Dates",
  "status": "draft",
  "creationDate": "2014-08-13T10:13:39.399Z",
  "body": "TBD"
}

This is great. Notice that the service has automatically serialized the creation date to an ISO-8601 compliant string. I couldn’t ask for more… or could I?

What if I want to now get that post back:

$http.get("/api/blog/123").success (blog) ->
    console.log blog.creationDate    
    console.log typeof blog.creationDate

Assuming that the endpoint returns the exact same JSON that was just posted, this code will output:

2014-08-13T10:13:39.399Z
string

This is not the end of the world but it may not be what one is expecting. The expectation is usually that if I put a Date instance into a serialization function, then I get a Date instance out of the matching deserialization function.

Fortunately, this situation is easily remedied with a Angular http interceptor. Angular’s $httpProvider service allows one to configure interceptors that can pre-process all out-going requests before they are sent and post-process all received responses before handing them back to the calling application. A response post-processor to find all ISO-8601 date strings and convert them to actual Date objects is easy to implement.

angular.module('myModule', []).config([
  '$httpProvider'
  ($httpProvider) ->
    $httpProvider.interceptors.push [
      ->
        #Matches YYYY-MM-ddThh:mm:ss.sssZ where .sss is optional
        iso8601RegEx = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/
 
        response: (response) ->
 
          convertDates = (obj) ->
 
            for key, value of obj
 
              #If it is a string of the expected form convert to date  
              type = typeof value
              if type is 'string' and iso8601RegEx.test value
                  obj[key] = new Date(value)
 
              #Recursively evaluate nested objects
              else if type is 'object'
                convertDates value
 
          convertDates response.data
 
          response
    ]
])

And there you have it. Happy coding!