login register Sysop! about ME  
qrcode
    최초 작성일 :    2014년 02월 27일
  최종 수정일 :    2014년 02월 27일
  작성자 :    kkyjudang
  편집자 :    kkyjudang (김 경용)
  읽음수 :    23,740

강좌 목록으로 돌아가기

필자의 잡담~

이번 번역컬럼은 김경용 님이 번역해주신 컬럼이며, RESTful 웹 서비스와 AngularJS 팩토리(Factory)를 연동하여 사용하는 방법에 대해서 설명하고 있습니다.
본 번역문서는 개인적인 취지로 번역되어 제공되는 문서로, 원문을 비롯한 모든 저작권은 마이크로소프트사에 있습니다. 마이크로소프트사의 요청이 있을 경우, 언제라도 게시가 중단될 수 있습니다. 본 번역문서에는 오역이 포함되어 있을 수 있으며 주석도 번역자 개인의 견해일뿐입니다. 마이크로소프트사는 본 문서의 번역된 내용에 대해 일체의 보장을 하지 않습니다. 번역이 완료된 뒤에도 제품이 업그레이드 되거나 기능이 변경됨에 따라 원문도 변경되거나 보완되었을 수 있으므로 참고하시기 바랍니다.
본 번역문서의 원문은 Using an AngularJS Factory to Interact with a RESTful Service 입니다.

RESTful 웹 서비스와 연동하는 AngularJS 팩토리(Factory) 사용하기

AngularJS를 처음 접하시는 분들은 저의 60여분의 AngularJS 소개 동영상 강좌 또는 free eBook을 참조해 주십시오. 또한, AngluarJS를 이용해서 SPA(Single Page Applications)를 개발하는 최근의 동향이 궁금하다면 The AngularJS Magazine도 참고해 보시기 바랍니다.

이 컬럼에서 다루게 될 내용은?

  • RESTful Service 생성하기
  • AngularJS 모듈(Module) 생성하기
  • AngluarJS 팩토리(Factory) 생성하기
  • AngluarJS 컨트롤러(Controller) 생성하기

AngularJS는 SPA(Single Page Applications, 단일 페이지 응용프로그램)를 개발하기 위한 강력하고도 훌륭한 프레임워크(framework)을 제공할 뿐만 아니라 라우팅, MV*-스타일 프로그래밍, 서비스(services), 팩토리(factories), 모듈(modules), 테스팅 등을 내장 기술로서 제공합니다. Angular는 사실상 어떠한 HTTP 자원이던 연계하여 사용이 가능하지만, 이번 컬럼에서는 ASP.NET Web API기술을 사용하여 작성된 RESTful API와 연동(참고로 어떠한 백앤드 서비스와도 사용이 가능합니다) 하는 것만을 중점적으로 다루려고 합니다. jQuery를 사용해보셨다면 $.getJSON() 또는 $.ajax()와 같은 함수 호출을 해보셨을 겁니다. Angular는 jQuery와의 혼용에 문제가 없긴 하지만, 쉽게 사용할 수 있도록 내장된 HTTP 기능을 제공할 뿐만 아니라 팩토리(factories)나 서비스(services)를 이용하여 데이터 기능을 캡슐화(encapsulate)할 수 있는 Angular만의 독창적인 방법도 제공하기에 굳이 jQuery를 혼용하여 사용할 필요가 없습니다.

이번 컬럼에서는 AngulaJS의 몇 가지 핵심기능에 대해 짧게 검토를 해 볼 예정입니다. 다시 말하자면, 모듈(modules), 라우터(routes), 팩토리(factories) 그리고 컨트롤러(controllers)에 대해 살펴볼까 합니다. 그리고, 컨트롤러(controllers)에서 호출될 수 있는 팩토리(factories) 안에 데이터 관련 기능(RESTful서비스 호출과 같은)을 어떻게 캡슐화(encapsulate)할 수 있는지도 살펴볼까 합니다.

image


우선 ASP.NET Web API로 작성된 기본적인 백앤드 서비스를 살펴보는 것으로부터 컬럼을 시작해 보겠습니다. 그런 다음, 특정 서비스와 통신하는 팩토리를 포함하여 몇 가지 AngularJS기능들을 알아보도록 하겠습니다.

RESTful Service 생성하기

ASP.NET Web API는 다양한 클라이언트에게 데이터를 제공하는 훌륭한 백앤드 프레임워크입니다. 이번 컬럼에서는 ASP.NET Web API를 이용하여 JSON데이터를 제공하는 방법만을 다루겠지만, 사실 Web API는 XML 뿐만 아니라 이미지 심지어는 어떠한 형태의 다양한 형식까지도 서비스가 가능합니다. 다음은 고객(Customer)과 주문(order) 내역들을 클라이언트에게 제공하는 간단한 서비스 예제입니다. 이 서비스는 웹 클라이언트로부터 호출될 때 자동으로 JSON데이터를 반환해줍니다.

public class CustomersController : ApiController
{
    ICustomerRepository _Repository;

    public CustomersController()
    {
        //CustomerRepository could be injected if desired
        _Repository = new CustomerRepository();
    }

    // GET api/customers
    public HttpResponseMessage Get()
    {
        var custs = _Repository.GetCustomers();
        if (custs == null) throw new HttpResponseException(HttpStatusCode.NotFound);
        return Request.CreateResponse<IEnumerable<Customer>>(HttpStatusCode.OK, custs);
    }

    // GET api/customers/5
    public HttpResponseMessage Get(int id)
    {
        var cust = _Repository.GetCustomer(id);
        if (cust == null) throw new HttpResponseException(HttpStatusCode.NotFound);
        return Request.CreateResponse<Customer>(HttpStatusCode.OK, cust);
    }

    // POST api/customers
    public HttpResponseMessage Post([FromBody]Customer cust)
    {
        var newCust = _Repository.InsertCustomer(cust);
        if (newCust != null)
        {
            var msg = new HttpResponseMessage(HttpStatusCode.Created);
            msg.Headers.Location = new Uri(Request.RequestUri + newCust.ID.ToString());
            return msg;
        }
        throw new HttpResponseException(HttpStatusCode.Conflict);
    }

    // PUT api/customers/5
    public HttpResponseMessage Put(int id, [FromBody]Customer cust)
    {
        var status = _Repository.UpdateCustomer(cust);
        if (status) return new HttpResponseMessage(HttpStatusCode.OK);
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    // DELETE api/customers/5
    public HttpResponseMessage Delete(int id)
    {
        var status = _Repository.DeleteCustomer(id);
        if (status) return new HttpResponseMessage(HttpStatusCode.OK);
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    [HttpGet]
    public List<Order> Orders(int custID)
    {
        var orders = _Repository.GetOrders(custID);
        if (orders == null) 
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound)); return orders; } }


위의 코드에는 주요한 역할인 GET, PUT, POST, DELETE 연산을 처리하는 메소드(methods)가 모두 포함되어 있음을 볼 수 있습니다. 또한, 각각의 메소드(method)는 내부적으로 repository 객체를 사용하여 실제 데이터 소스와 연동하는 것을 볼 수 있습니다. ASP.NET Web API를 이용하여 서비스를 구현하는 더 많은 다양한 내용의 강좌 및 컬럼은 Web API사이트를 참고하시기 바랍니다.

이제 클라이언트 입장으로 돌아가서, 위에서 정의된 서비스가 어떻게 AngularJS에서 사용되는지 알아봅시다.

AngularJS 모듈(Module) 생성하기


AngularJS는 데이터 기능을 캡슐화(encapsulating)하기 위해 서비스(services), 팩토리(factories), 프로바이더(providers)를 포함하는 다양한 옵션을 제공합니다. 이 예제에서는 제가 개인적으로 선호하는 팩토리(factories)와 프레임워크가 제공하는 내장 객체 중 하나인 $http에 대해 살펴보고자 합니다. 다만 팩토리(factory) 코드를 검토하기에 앞서, 이번 컬럼 내내 계속해서 언급하게 될 애플리케이션을 구성하고 있는 모듈(module)에 대하여 먼저 잠깐 살펴보겠습니다. :

var app = angular.module('customersApp', ['ngRoute']);
app.config(['$routeProvider', function ($routeProvider) {
    $routeProvider.when('/', {
        controller: 'customersController',
        templateUrl: '/app/views/customers.html'
    })
    .otherwise({ redirectTo: '/' });
}]);


예제에서 customersApp 모듈(module)은 곧 언급할 팩토리(factory)처럼 다른 구성요소들(components)을 위한 컨테이너로서 동작하기 위해 생성되고 있습니다. 또한, 예제에서는 customersApp 모듈(module)을 정의하고 있을 뿐만 아니라 라우팅(routing)을 처리하는 'ngRoute' 모듈(module)도 참조하고 있습니다. 이 모듈(module)은 AngularJS 1.2에서 새롭게 추가된 angular-route.js파일 안에 포함되어 있습니다.

이 모듈은 일단 정의되면 애플리케이션에 대한 라우팅을 구성하는데 사용됩니다. 라우팅 구성은 $routeProvider객체를 인자로 갖는 config() 함수를 호출함으로써 이루어지는데요. 이번 예제에서는 간단하게 루트 경로를 처리하도록 한가지 라우팅만을 설정하고 있지만 $routeProvider.when() 함수를 사용하여 추가적인 라우팅 규칙을 설정할 수도 있습니다.

이제 모듈(module)은 생성되었습니다. 그렇기에 다음으로는 어떻게 팩토리(factory)를 생성하는지 그리고 이를 사용하여 어떻게 ASP.NET Web API를 호출하는지 알아보도록 합시다.

AngularJS 팩토리(Factory) 생성하기

AngularJS 컨트롤러(controllers)가 백엔드 서비스들을 직접 호출하는 것이 가능하긴 하지만, 저는 개인적으로 이런 류의 기능들은 좀 더 재사용 가능하고 유지보수가 쉽도록, 팩토리 안에 정의하는 것을 선호합니다. 이번 애플리케이션에서는 ASP.NET Web API서비스를 호출하는 dataFactory라는 이름의 팩토리(factory)를 살펴보도록 하겠습니다.

AngularJS의 팩토리 개념을 처음 접한 분들을 위해서 부연설명을 드리자면 팩토리는 angular.module('YourModule').factory() 함수를 호출함으로써 생성됩니다(모듈은 서비스(services), 프로바이더(providers), 값들(values), 그리고 상수들(constants)도 생성할 수 있습니다).

image

팩토리(factory)는 데이터 처리, 비즈니스 규칙 정합성체크, 또는 그 외의 여러 다양한 처리를 위해 사용 가능한 객체를 생성하고 반환할 책임이 있습니다. Angular 팩토리는 기본적으로 싱글톤(singleton)입니다. 그래서 팩토리에 의해 반환된 객체는 애플리케이션에 의해 재사용이 가능합니다.

다음은 GET, PUT, POST, DELETE를 처리하는 팩토리가 ASP.NET Web API 서비스를 호출하는 예제입니다. 이 팩토리는 서버로의 호출을 수행하는 객체를 생성하고 있습니다.

angular.module('customersApp')
    .factory('dataFactory', ['$http', function($http) {
    var urlBase = '/api/customers';
    var dataFactory = {};
    dataFactory.getCustomers = function () {
    return $http.get(urlBase);
    };
    dataFactory.getCustomer = function (id) {
    return $http.get(urlBase + '/' + id);
    };
    dataFactory.insertCustomer = function (cust) {
    return $http.post(urlBase, cust);
    };
    dataFactory.updateCustomer = function (cust) {
    return $http.put(urlBase + '/' + cust.ID, cust)
    };
    dataFactory.deleteCustomer = function (id) {
    return $http.delete(urlBase + '/' + id);
    };
    dataFactory.getOrders = function (id) {
    return $http.get(urlBase + '/' + id + '/orders');
    };
    return dataFactory;
}]);

$http 객체는 AngularJS에 의해 런타임에 팩토리 안에 주입됩니다. 그리고 서버로의 AJAX 호출을 만들기 위해 사용됩니다. 코드를 통해서 보여지는 것처럼 get(), post(), put(), delete() 함수들이 노출되고 있으며, RESTful 서비스와 아주 쉽게 연계되는 것을 볼 수 있습니다. 이 팩토리 안에 정의된 함수들은 데이터를 가지고 무엇을 해야 할 지 모르기 때문에, 각각의 함수는 콜백 함수들을 호출하는 promise를 반환합니다.

위에서 언급한 것처럼 팩토리들은 기본적으로 싱글톤입니다. 따라서, 팩토리에 의해 반환되는 객체는 애플리케이션 안에서 다른 컨트롤러들에 의해 반복해서 재사용이 가능합니다. 사실, AngulaJS 서비스(service)도 이와 같은 기능들을 수행하도록 사용될 수 있지만 서비스는 그 자신의 인스턴스를 반환하기에(서비스 역시 싱글톤입니다), 결과로 'this' 키워드를 사용해야 합니다. 또한, 서비스와 비교하여 팩토리는 팩토리 함수 안에 자신만의 객체를 마음대로 생성하고 쉽게 반환할 수 있다는 장점이 있습니다.

좀 더 확실하게 팩토리와 서비스의 차이를 비교해 보기 위해서 앞서 작성한 팩토리를 서비스로 작성해 보도록 하겠습니다. 다음은 그렇게 작성한 dataSevice라는 서비스 예제를 살펴봅시다. 서비스 안에 정의된 함수가 호출자(caller)에게로 반환되는 객체인 점에 주목하시기 바랍니다. 팩토리의 경우는 함수 안에서 정의된 객체인 반면에 말입니다.

angular.module('customersApp')
    .service('dataService', ['$http', function ($http) {
    var urlBase = '/api/customers';
    this.getCustomers = function () {
    return $http.get(urlBase);
        };
    this.getCustomer = function (id) {
    return $http.get(urlBase + '/' + id);
        };
    this.insertCustomer = function (cust) {
    return $http.post(urlBase, cust);
        };
    this.updateCustomer = function (cust) {
    return $http.put(urlBase + '/' + cust.ID, cust)
        };
    this.deleteCustomer = function (id) {
    return $http.delete(urlBase + '/' + id);
        };
    this.getOrders = function (id) {
    return $http.get(urlBase + '/' + id + '/orders');
        };
    }]);

AngularJS 컨트롤러(Controller) 생성하기

이제 생성된 팩토리를 통해서 컨트롤러가 ASP.NET Web API 서비스를 호출하기 위해 어떻게 사용될 수 있는지 살펴보겠습니다. 다음은 customersController라는 컨트롤러 예제이며, "dataFacotry" 팩토리에 의존하여 데이터 조회와 갱신을 처리하게 됩니다.

dataFactory안의 모든 함수들은 이 컨트롤러가 사용하는 success()와 error() 함수에 의해 동기화되는 promise 객체를 반환합니다. 팩토리로부터 성공적으로 데이터가 반환되면 $scope는 업데이트되고 사용자 인터페이스를 갱신하게 됩니다.

angular.module('customersApp')
    .controller('customersController', ['$scope', 'dataFactory', 
    function ($scope, dataFactory) {
    $scope.status;
    $scope.customers;
    $scope.orders;
    getCustomers();
    function getCustomers() {
        dataFactory.getCustomers()
            .success(function (custs) {
                $scope.customers = custs;
            })
            .error(function (error) {
                $scope.status = 'Unable to load customer data: ' + error.message;
            });
    }
    $scope.updateCustomer = function (id) {
    var cust;
    for (var i = 0; i < $scope.customers.length; i++) {
    var currCust = $scope.customers[i];
    if (currCust.ID === id) {
                cust = currCust;
    break;
            }
        }
        dataFactory.updateCustomer(cust)
          .success(function () {
              $scope.status = 'Updated Customer! Refreshing customer list.';
          })
          .error(function (error) {
              $scope.status = 'Unable to update customer: ' + error.message;
          });
    };
    $scope.insertCustomer = function () {
    //Fake customer data
    var cust = {
            ID: 10,
            FirstName: 'JoJo',
            LastName: 'Pikidily'
        };
        dataFactory.insertCustomer(cust)
            .success(function () {
                $scope.status = 'Inserted Customer! Refreshing customer list.';
                $scope.customers.push(cust);
            }).
            error(function(error) {
                $scope.status = 'Unable to insert customer: ' + error.message;
            });
    };
    $scope.deleteCustomer = function (id) {
        dataFactory.deleteCustomer(id)
        .success(function () {
            $scope.status = 'Deleted Customer! Refreshing customer list.';
    for (var i = 0; i < $scope.customers.length; i++) {
    var cust = $scope.customers[i];
    if (cust.ID === id) {
                    $scope.customers.splice(i, 1);
    break;
                }
            }
            $scope.orders = null;
        })
        .error(function (error) {
            $scope.status = 'Unable to delete customer: ' + error.message;
        });
    };
    $scope.getCustomerOrders = function (id) {
        dataFactory.getOrders(id)
        .success(function (orders) {
            $scope.status = 'Retrieved orders!';
            $scope.orders = orders;
        })
        .error(function (error) {
            $scope.status = 'Error retrieving customers! ' + error.message;
        });
    };
}]);

마무리 요약


AngularJS는 어떠한 백엔드 서비스와도 상호 연동할 수 있으며 그를 위해 필요한 모든 구성요소를 포함하고 있습니다. 이 컬럼을 통해서 여러분은 $http객체가 어떻게 간단히 RESTful ASP.NET Web API서비스를 호출하는데 사용되는지 알아봤습니다. 또한, 팩토리(또는 서비스)를 사용하여 어떻게 데이터를 캡슐화하여 재사용이 가능하도록 만드는 지도 살펴보았습니다.

이번 예제에서는 ASP.NET Web API를 사용하였지만, 마찬가지로 AngularJS코드는 Node.js, Python, 또는 다른 종류의 언어나 프레임워크를 사용하여 작성된 어떠한 백엔드 서비스도 호출이 가능합니다.

여기에서 보여드린 예제는 비교적 간단했지만, 이를 통해 여러분이 AngularJS와 백엔드 서비스 연동을 시작해 보실 수 있게 되길 바랍니다.


authored by

  kkyjudang
  2014-02-27(12:53)
캐릭 이미지
처음하는 번역이라 좌충우돌이 없지않았으나, 태오님의 큰 도움을 받고서야 읽힐만한 컬럼이 되었습니다. 다시한번 태오님께 감사드립니다. 모쪼록 시간내어 읽는 분들께 작은 도움이라도 되길 기원합니다.
  monarch7
  2014-02-27(17:23)
캐릭 이미지
감사합니다. 잘보겠습니다. ^^

 
 
.NET과 Java 동영상 기반의 교육사이트

로딩 중입니다...

서버 프레임워크 지원 : NeoDEEX
based on ASP.NET 3.5
Creative Commons License
{5}
{2} 읽음   :{3} ({4})