-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathatom.xml
More file actions
2358 lines (1793 loc) · 171 KB
/
atom.xml
File metadata and controls
2358 lines (1793 loc) · 171 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Remotty Tech Blog]]></title>
<link href="http://remotty.github.io/atom.xml" rel="self"/>
<link href="http://remotty.github.io/"/>
<updated>2014-01-30T17:21:06+09:00</updated>
<id>http://remotty.github.io/</id>
<author>
<name><![CDATA[Remotty Group]]></name>
<email><![CDATA[admin@remotty.com]]></email>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[Angularjs Providers]]></title>
<link href="http://remotty.github.io/blog/2014/01/29/angularjs-providers/"/>
<updated>2014-01-29T13:55:27+09:00</updated>
<id>http://remotty.github.io/blog/2014/01/29/angularjs-providers</id>
<content type="html"><![CDATA[<h2><strong>AngularJS에서 Provider 간의 차이점</strong></h2>
<p><a href="http://bit.ly/19ZQTHy">http://bit.ly/19ZQTHy</a> (한글번역)</p>
<!--more-->
<p>provider vs factory vs service</p>
<h3>Provider란 무엇인가?</h3>
<p>AngularJS docs 에는 아래와 같이 정의되어 있다.</p>
<blockquote><p>$get 메소드를 가지는 하나의 객체이다. injector는 바로 이 $get 메소드를 호출해서 새로운 서비스를 생성하게 되는 것이다. <code>provider</code>는 설정을 통해서 이와 같은 메소드를 추가할 수 있다.</p></blockquote>
<p>AngularJS는 <code>$provide</code>를 이용해서 새로운 <code>provider</code>를 등록한다. <code>provider</code>는 기본적으로 새로운 인스턴스를 생성하지만 <code>provider</code>당 하나의 인스턴스만 만들게 된다(singleton). <code>$provide</code>는 6개의 메소드를 사용해서 커스텀 <code>provider</code>를 생성하게 되는데, 각각에 대해서 샘플 코드와 함께 설명할 것이다. 아래의 <code>provider</code>는 <code>$provide</code> 상에서 사용할 수 있다.</p>
<ul>
<li>constant</li>
<li>value</li>
<li>service</li>
<li>factory</li>
<li>decorator</li>
<li>provider</li>
</ul>
<h2>Constant</h2>
<p><code>constant(상수)</code>는 모든 곳에 inject(주입)할 수 있다. 상수는 그 값을 변경할 수 없다.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">angular</span><span class="p">.</span><span class="nx">module</span><span class="p">(</span><span class="s1">'app'</span><span class="p">,</span> <span class="p">[]);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">config</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">$provide</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">$provide</span><span class="p">.</span><span class="nx">constant</span><span class="p">(</span><span class="s1">'movieTitle'</span><span class="p">,</span> <span class="s1">'The Matrix'</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">controller</span><span class="p">(</span><span class="s1">'ctrl'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">movieTitle</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">movieTitle</span><span class="p">).</span><span class="nx">toEqual</span><span class="p">(</span><span class="s1">'The Matrix'</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<p>AngularJS는 상수를 만들기 위한 편리한 방법을 제공해 주어 코드를 단축할 수 있다.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">constant</span><span class="p">(</span><span class="s1">'movieTitle'</span><span class="p">,</span> <span class="s1">'The Matrix'</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>
<h2>Value</h2>
<p><code>value</code>는 <code>configuration(설정)</code>로 주입할 수 없지만 값을 변경할 수는 있다.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">angular</span><span class="p">.</span><span class="nx">module</span><span class="p">(</span><span class="s1">'app'</span><span class="p">,</span> <span class="p">[]);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">config</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">$provide</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">$provide</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="s1">'movieTitle'</span><span class="p">,</span> <span class="s1">'The Matrix'</span><span class="p">)</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">controller</span><span class="p">(</span><span class="s1">'ctrl'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">movieTitle</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">movieTitle</span><span class="p">).</span><span class="nx">toEqual</span><span class="p">(</span><span class="s1">'The Matrix'</span><span class="p">);</span>
</span><span class='line'><span class="p">})</span>
</span></code></pre></td></tr></table></div></figure>
<p>AngularJS는 <code>value</code>를 만들기 위한 편리한 방법을 제공해 주어 코드를 단축할 수 있다.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="s1">'movieTitle'</span><span class="p">,</span> <span class="s1">'The Matrix'</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>
<h2>Service</h2>
<p><code>service</code>란 주입이 가능한 <code>constructor(생성자)</code>이다. 원할 경우, 함수에 필요한 dependency를 명시할 수 있다. <code>service</code>는 하나의 singleton이기 때문에 AngularJS가 한번만 생성하게 될 것이다. <code>service</code>는 데이터를 공유하는 것 같은 컨트롤러간의 통신을 위한 좋은 방법이다.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">angular</span><span class="p">.</span><span class="nx">module</span><span class="p">(</span><span class="s1">'app'</span> <span class="p">,[]);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">config</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">$provide</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">$provide</span><span class="p">.</span><span class="nx">service</span><span class="p">(</span><span class="s1">'movie'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">this</span><span class="p">.</span><span class="nx">title</span> <span class="o">=</span> <span class="s1">'The Matrix'</span><span class="p">;</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">controller</span><span class="p">(</span><span class="s1">'ctrl'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">movie</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">movie</span><span class="p">.</span><span class="nx">title</span><span class="p">).</span><span class="nx">toEqual</span><span class="p">(</span><span class="s1">'The Matrix'</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<p>AngularJS는 <code>service</code>를 만들기 위한 편리한 방법을 제공해 주어 코드를 단축할 수 있다.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">service</span><span class="p">(</span><span class="s1">'movie'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">this</span><span class="p">.</span><span class="nx">title</span> <span class="o">=</span> <span class="s1">'The Matrix'</span><span class="p">;</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<h2>Factory</h2>
<p><code>factory</code>는 주입이 가능한 함수이다. <code>factory</code>는 singleton이고 dependency를 함수내에 명시할 수 있다는 점에서 <code>service</code>와 많은 부분에서 흡사하다. 차이점은 <code>factory</code>는 일반 함수를 주입해서 AngularJS가 호출하도록 하는 것이고 <code>service</code>는 <code>constructor</code>를 주입한다는 것이다. <code>constructor</code>는 새로운 객체를 만들기 때문에 <code>service</code>내에서는 <code>new</code> 메소드를 호출하지만, <code>factory</code>를 사용하면 함수가 어떤 형태의 것이라고 반환할 수 있도록 해 준다. 나중에 알게 되겠지만, <code>factory</code>는 <code>$get</code> 메소드만을 가지는 <code>provider</code>이다.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">angular</span><span class="p">.</span><span class="nx">module</span><span class="p">(</span><span class="s1">'app'</span><span class="p">,</span> <span class="p">[]);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">config</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">$provide</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">$provide</span><span class="p">.</span><span class="nx">factory</span><span class="p">(</span><span class="s1">'movie'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">title</span><span class="o">:</span> <span class="s1">'The Matrix'</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">controller</span><span class="p">(</span><span class="s1">'ctrl'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">movie</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">movie</span><span class="p">.</span><span class="nx">title</span><span class="p">).</span><span class="nx">toEqual</span><span class="p">(</span><span class="s1">'The Matrix'</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<p>AngularJS는 <code>factory</code>를 생성하는 편리한 방법을 제고해 주어 아래와 같이 단축할 수 있다.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">factory</span><span class="p">(</span><span class="s1">'movie'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">title</span><span class="o">:</span> <span class="s1">'The Matrix'</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<h2>Decorator</h2>
<p><code>decorator</code>는 다른 <code>provider</code>를 변경하거나 encapulation할 수 있다. 그러나 하나의 예외가 있는데, <code>constant</code>는 decorate 할 수 없다는 것이다.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">angular</span><span class="p">.</span><span class="nx">module</span><span class="p">(</span><span class="s1">'app'</span><span class="p">,</span> <span class="p">[]);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="s1">'movieTitle'</span><span class="p">,</span> <span class="s1">'The Matrix'</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">config</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">$provide</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">$provide</span><span class="p">.</span><span class="nx">decorator</span><span class="p">(</span><span class="s1">'movieTitle'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">$delegate</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">$delegate</span> <span class="o">+</span> <span class="s1">' - starring Keanu Reeves'</span><span class="p">;</span>
</span><span class='line'> <span class="p">});</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">controller</span><span class="p">(</span><span class="s1">'myController'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">movieTitle</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">movieTitle</span><span class="p">).</span><span class="nx">toEqual</span><span class="p">(</span><span class="s1">'The Matrix - starring Keanu Reeves'</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<h2>Provider</h2>
<p><code>provider</code>는 모든 <code>provider</code> 중에서 가장 유연한 메소드이다. 이 메소드를 이용하면 복잡한 생성 함수에 다양한 옵션을 가지도록 할 수 있다. <code>provider</code>는 실제로 구성을 변경할 수 있는 <code>factory</code>이다. <code>provider</code>는 하나의 객체나 <code>constructor</code>를 취하게 된다.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">angular</span><span class="p">.</span><span class="nx">module</span><span class="p">(</span><span class="s1">'app'</span><span class="p">,</span> <span class="p">[]);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">provider</span><span class="p">(</span><span class="s1">'movie'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">version</span><span class="p">;</span>
</span><span class='line'> <span class="k">return</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">setVersion</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">version</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'> <span class="nx">$get</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">title</span><span class="o">:</span> <span class="s1">'The Matrix'</span> <span class="o">+</span> <span class="s1">' '</span> <span class="o">+</span> <span class="nx">version</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">config</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">movieProvider</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">movieProvider</span><span class="p">.</span><span class="nx">setVersion</span><span class="p">(</span><span class="s1">'Reloaded'</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">controller</span><span class="p">(</span><span class="s1">'ctrl'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">movie</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">expect</span><span class="p">(</span><span class="nx">movie</span><span class="p">.</span><span class="nx">title</span><span class="p">).</span><span class="nx">toEqual</span><span class="p">(</span><span class="s1">'The Matrix Reloaded'</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<h2>요약</h2>
<ul>
<li>모든 <code>providers</code>들은 단 한번만 인스턴스화 된다. 즉, singleton 이라는 것이다.</li>
<li><code>constant</code>를 제외한 모든 <code>provider</code>는 decorate할 수 있다.</li>
<li><code>constant</code>은 어느 곳이나 주입할 수 있는 값을 가지만, 수정할 수 없다.</li>
<li><code>value</code>는 간단하게 주입할 수 있는 값이다.</li>
<li><code>service</code>는 주입할 수 있는 <code>constructor</code>이다.</li>
<li><code>factory</code>는 주입할 수 있는 함수이다.</li>
<li><code>decorator</code>는 <code>constant</code>를 제외한 모든 <code>provider</code>를 변경하거나 encapuslation할 수 있다.</li>
<li><code>provider</code>는 구성요소를 설정할 수 있는 <code>factory</code>이다.</li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[RestFul이란 무엇인가?]]></title>
<link href="http://remotty.github.io/blog/2014/01/28/lets-study-rest/"/>
<updated>2014-01-28T23:55:43+09:00</updated>
<id>http://remotty.github.io/blog/2014/01/28/lets-study-rest</id>
<content type="html"><![CDATA[<p>이 글에서는 <strong><a href="http://ko.wikipedia.org/wiki/REST">REST(Representational State Transfer)</a></strong>에 대해서 알아보겠습니다.</p>
<!--more-->
<p><a name="tableOfContent"></a></p>
<h3>목차</h3>
<ul>
<li><a href="#prologue">머리말</a></li>
<li><a href="#uri">URI 설계하기</a>
<ul>
<li><a href="#lowercase">소문자를 사용하자</a></li>
<li><a href="#hyphen">하이픈을 사용하자</a></li>
<li><a href="#extension">확장자를 사용하지 말자</a></li>
<li><a href="#crud">CRUD는 URI에 사용하면 안된다</a></li>
</ul>
</li>
<li><a href="#collectionDocument">컬렉션과 도큐먼트</a></li>
<li><a href="#method">HTTP Method의 알맞은 역할</a></li>
<li><a href="#responsive">반응형 웹에서의 REST</a></li>
<li><a href="#i18n">I18n과 REST</a></li>
<li><a href="#status">응답 상태 코드</a>
<ul>
<li><a href="#statusSuccess">성공</a>
<ul>
<li><a href="#200">200</a></li>
<li><a href="#201">201</a></li>
<li><a href="#202">202</a></li>
<li><a href="#204">204</a></li>
</ul>
</li>
<li><a href="#statusFail">실패</a>
<ul>
<li><a href="#400">400</a></li>
<li><a href="#401">401</a></li>
<li><a href="#403">403</a></li>
<li><a href="#404">404</a></li>
<li><a href="#405">405</a></li>
</ul>
</li>
<li><a href="#statusEtc">기타</a></li>
</ul>
</li>
<li><a href="#epilogue">마치며</a></li>
<li><a href="#reference">참고자료</a></li>
</ul>
<p><a name="prologue"></a></p>
<h3>머리말</h3>
<p>바로 위에서 REST에 대해서 알아본다고 하였지만, <strong>REST의 정의와 같은 것은 생략할 예정</strong>입니다. 진짜로 이글에서 다룰 것은 실제 <strong>RESTFul한 API를 작성할 때 도움될만한 것들을 공부</strong>합니다. 또한 여러가지 규칙이 있지만 어느 규칙이 진짜이고, 표준화 된것이 없기때문에(이런것으로 알고있습니다.) 실제 많은 사이트들이 약간씩은 다른 형태로 REST API를 운영하고있습니다. 이 글에서도 <strong>필자가 중요하다고 생각하고 직관적이라고 생각하는 요소들을 선택 하여 소개 또는 설명 할 예정</strong>입니다.</p>
<p>요즘은 예전과 달리 소비를 위한 장비 및 프로그램이 다양합니다. 반대로 말하면 예전에는 어떠한 인터넷 컨텐츠를 소비하기위한 장비나 프로그램이 몇개 없었습니다. 그렇기때문에 서버와 클라이언트가 거의 1:1이였습니다. 그러나 요즘은 역시 서버는 1인데 클라이언트가 굉장히 다양해졌습니다. 안드로이드는 OS 버전도 굉장히 다양하고 단말기마다 굉장히 다른 특성을 갖기도 합니다. 또 IOS도 있고, 컴퓨터 브라우져의 종류도 많아졌죠.</p>
<p>그래서 예전처럼 <strong>하나의 클라이언트를 위한 서버를 구성하는건 비효율적인 일</strong>이 되어버렸습니다. 하나의 서버로 여러대의 클라이언트를 대응하도록 할때 필요한것이 RESTFul API입니다.</p>
<p><a name="uri"></a></p>
<h3>URI 설계하기</h3>
<p>일단 <a href="http://en.wikipedia.org/wiki/Uniform_resource_identifier">URI(Uniform Resource Identifier)</a>란 영어 약자를 풀어보면 ‘균등한 리소스 식별자’정도로 할 수 있습니다. 말그대로 인터넷의 어떠한 리소스를 식별하기 위해서 만들어진 것입니다. 잘 감이 안오는데 중간중간 특성들을 이야기하면서 내용을 보강하겠습니다.</p>
<p>밑에서 설명하는 규칙들은 <a href="http://www.rfc-editor.org/rfc/rfc3986.txt">RFC3986</a>을 기반으로 작성되었습니다.</p>
<p><a name="lowercase"></a></p>
<h5>소문자를 사용하자(최소한 대소문자를 구분한다는 사실을 알고있자)</h5>
<pre><code>http://www.example.com:80/users/1?q=abc#title
|________________________|_______|__________|
1 2 3
URI는위와같이 크게 3부분으로 나뉘어져있습니다.
rfc3986에서는 1번부분(host와 port)을 제외한 2번 3번 부분은 대소문자를 구분하도록 하였습니다.
</code></pre>
<p>즉</p>
<pre><code>a - http://abc.com/haha
b - HTTP://ABC.COM/haha
c - http://abc.com/HAHA
d - http://abc.com/hAhA
</code></pre>
<p>위 예제에서 a와 b만 같은 리소스이고 나머지 조합은 전부 다른 리소스입니다. 그러므로 대소문자를 섞어서 사용하는건 혼란을 가져올 수 있으므로 지양해야겠습니다. 그래도 URI에 사람이름과 같은 고유명사가 들어갈 수 도있죠.. 이땐 대문자를 쓰고싶은데… 사용해도 되긴합니다만 대소문자가 구분된다는걸 이해하셔야 합니다. 위 설명과 중복되긴 하지만 다시한번 언급하겠습니다.</p>
<pre><code>http://www.remotty.com/countries/korea
http://www.remotty.com/countries/Korea
</code></pre>
<p>위 두개의 URI는 분명히 다른 리소스를 가리키고 있는 것입니다.</p>
<p>다만 국가코드를 포함하여 도메인을 의미있게 하기위해서 이와 같은 형태로 사용하는 것은 굉장히 좋다고 봅니다. <code>http://cleanHo.me</code>, <code>http://adBy.me</code>, <code>http://dishBy.me</code>, <code>http://googleSear.ch</code> 이 경우에도 경로(path)부분은 소문자를 사용하는게 좋겠습니다.</p>
<p><a name="hyphen"></a></p>
<h5>하이픈(–, hyphen)을 사용하자</h5>
<p>경로(path)에 공백(띄어쓰기)가 들어갈땐 경우에따라 띄어쓰기 대신 <code>%20</code>이 쓰일때가 있습니다. 이런건 보기에 별로 좋지 않기때문에 많은 사람들이 밑줄(_, underscore) 또는 하이픈(–, hyphen)을 사용하여 공백을 대체합니다. 여기서 권장하는건 하이픈만 사용하자 입니다. 보통 밑줄은 링크가 걸린부분에 표시되는데 그것과 중복되면 리소스로써의 밑줄은 가려질 수도있기때문에 하이픈을 사용하자.</p>
<p><a name="extension"></a></p>
<h5>확장자를 사용하지 말자</h5>
<p>기존의 많은 URI들이 확장자를 포함하고 있습니다. 하지만 REST API를 설계할때에는 확장자는 사용하지 않는게 좋겠습니다. 확장자를 사용하지 않으면 리소스가 더 유연해집니다. 어째든 확장자를 사용하지 않는다면 기존에 REST API를 접해보지 않는 사람들은 이런 의문을 갖을 수 있습니다?
결론적으로 <a href="https://tools.ietf.org/html/rfc2616#section-14.1">Accept</a> header를 사용해야 합니다. 예를들어 내용이 <code>Hello,World</code>인 파일이 있습니다. 서버를 기존방식대로 설계한다면 해당 파일은 <code>http://remotty.com/hello.txt</code>와 같이 요청하여 응답받을 것입니다. 기존의 방식은 분명하게 파일의 형태가 txt로 고정되어있습니다. csv 형태로도 제공하려면 <code>http://remotty.com/hello.csv</code> URI도 준비해야 할것이고, 서버엔 hello.txt와 hello.csv 두개의 파일이 존재 하게 될것입니다. <code>http://remotty.com/hello.txt</code>와 <code>http://remotty.com/hello.csv</code>는 분명하게 다른 리소스를 식별하는 URI이지만, 실제론 하나의 리소스를 가르키고 있습니다. 이것은 비 효율적입니다. 리소스가 한개라면 URI도 한개여야합니다.</p>
<p>REST API에서는 <code>http://remotty.com/hello</code>에 대한 대응만 해놓고, 해당 요청이 왔을때 <code>Accept</code> header를 적절히 파싱(parsing)하여 클라이언트(client)가 요청한대로 응답해주면 됩니다.</p>
<p>REST API로 구현했을땐</p>
<pre><code>GET /hello HTTP/1.1
Host: remotty.com
Accept: text/plain
</code></pre>
<p>또는</p>
<pre><code>GET /hello HTTP/1.1
Host: remotty.com
Accept: text/csv
</code></pre>
<p><code>Accept</code>를 좀더 적극적으로 활용한다면 이렇게도 가능합니다.</p>
<pre><code>GET /hello HTTP/1.1
Host: remotty.com
Accept: text/csv,text/html;q=0.5,application/xml;q=0.6,text/plain;q=0.9,application/pdf,*/*;q=0.3
</code></pre>
<p><code>Accept</code> header은 클라이언트가 자신이 선호하는 media type을 서버에 보내는 것입니다. 서버에 위 예제와 같은 요청이 왔다면 가장먼저 우선순위는 다음과 같습니다.</p>
<ol>
<li>text/csv</li>
<li>application/pdf</li>
<li>text/plain;q=0.9</li>
<li>application/xml;q=0.6</li>
<li>text/html;q=0.5</li>
<li>*/*;q=0.3</li>
</ol>
<p>q가 생략된것은 자동으로 1로 설정되며, <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.9">q의 범위</a>는 0부터 1입니다. 서버가 판단하여 csv로 응답을 할 수 있다면 csv로 응답을 하고 csv가 준비가 되지 않았다면 그다음 우선순위인 pdf로 pdf도 준비되지 않았다면 계속 다음으로 넘어가다가 서버가 응답할수있는 media type가 <code>Accept</code>에 명시되지 않았다면 <a href="http://tools.ietf.org/search/rfc2616#section-10.4.7">http status code 406</a>과 body엔 응답 가능한 media type를 명시하여 응답하여야 합니다. 더 자세한 내용은 <code>http content negotiation</code>으로 검색하시어 저도 좀 알려주시기 바랍니다.</p>
<p>위와 같이 <code>Accept</code> header를 적절히 잘 사용하면 하나의 URI로 클라이언트의 요청에 대한 응답을 좀더 유연하게 할 수 있습니다.</p>
<p><a name="crud"></a></p>
<h4>CRUD는 URI에 사용하면 안된다</h4>
<p>과거에 <code>GET</code>, <code>POST</code>만 사용하였을땐 CRUD를 URI에 표시해주어야 했습니다.</p>
<p>예를들면</p>
<pre><code>GET /posts/13/delete HTTP/1.1
POST /posts/write HTTP/1.1
GET /delete?id=55 HTTP/1.1
</code></pre>
<p>하지만 당신은 이제부터 REST API를 설계할 수 있습니다. 뒷부분에 나오는 <a href="#method">HTTP Method의 알맞은 역할</a>을 참조하여 적절한 Method를 사용하여 CRUD는 URI에 사용하지 않기로 합시다.</p>
<p><a name="collectionDocument"></a></p>
<h3>컬렉션과 도큐먼트</h3>
<p>이 글을 보기전 REST 관련된 글을 본적이 있다면 컬렉션(collection)이라고 이야기하는 도큐먼트(document)들의 집합을 들어보았을 겁니다. 도큐먼트는 우리말로 문서로 이해해도 되고, 정보라고 이해해도 무관합니다. 도큐먼트는 엘리먼트(element)라고도 하더라고요. 컬렉션은 정보(문서)들의 집합이 이라고 할 수 있겠네요. 컬렉션과 도큐먼트는 모두 리소스라고 표현할 수 있으며 URI에 나타납니다.</p>
<p>예제를 통해 이해도를 높여보겠습니다.</p>
<pre><code>http://www.remotty.com/sports/soccer
http://www.remotty.com/sports/soccer/players
http://www.remotty.com/sports/soccer/players/13/skills
</code></pre>
<p>위 URI를 요청하면 어떤 응답이 오게 될지 대충 예감이 오시나요…?</p>
<p><code>http://www.remotty.com/sports</code>는 컬렉션입니다. <code>sports</code>컬렉션에 <code>soccer</code>도큐먼트가 있는거고요. 또 <code>soccer</code>도큐먼트에 <code>player</code>이라는 컬렉션이 존재하는겁니다! <code>players</code> 컬렉션에 뭐 등번호가 <code>13</code>번인 선수가 있나봅니다. 여기서 <code>13</code>은 도큐먼트이고요. 아시겠죠…?
조금 더 이야기 해보겠습니다. <code>soccer</code> 도큐먼트와 동일한 수준의 다른 도큐먼트는 뭐가 있을까요…? <code>baseball</code>, <code>marathon</code> 등이 있겠네요. 그 하위의 <code>players</code>의 컬렉션과 동일한 수준의 컬렉션은 뭐가있을까요…? <code>rules</code>, <code>leagues</code> 등이 있겠네요. 이제 뭔지 아시겠죠…?</p>
<p>여기서… 중요한 법칙이랄꺼 까진 없지만 뭔가 있습니다. 바로 컬렉션은 복수로 사용하네요. 어쩌면 당연하지만 직관적인 REST API를 위해선 단수 복수도 정확하게 지켜주면 좋겠습니다. 요즘은 한글이 URI에 많이 들어가는데 <code>players</code>는 <code>선수들</code>로 하면 되려나요…?</p>
<p><a name="method"></a></p>
<h3>HTTP Method의 알맞은 역할</h3>
<p>HTTP Method는 여러가지가 있지만 REST API에서는 4개 혹은 5개의 Method만 사용됩니다. <code>POST</code>, <code>GET</code>, <code>PUT</code>, <code>DELETE</code> 이 4가지의 Method를 가지고 <a href="http://ko.wikipedia.org/wiki/CRUD">CRUD</a>를 할 수 있습니다. 그러나 REST API에서 사용되는 개수는 4개 혹은 5개라고 한 이유는 <code>PATCH</code>를 포함하면 5개가 됩니다.</p>
<p>각 Method마다 올바른 역할이 있습니다. 아래 표를 보면서 이해를 높이겠습니다.</p>
<pre><code>+--------------------------------------+------+-----+-----+--------+
| URI | POST | GET | PUT | DELETE |
+--------------------------------------+------+-----+-----+--------+
| http://www.remotty.com/sports | 1 | 2 | - | - |
+--------------------------------------+------+-----+-----+--------+
| http://www.remotty.com/sports/soccer | - | 3 | 4 | 5 |
+--------------------------------------+------+-----+-----+--------+
</code></pre>
<p>text table generator에서 만든 text table인데 한글을 사용하면 깨지므로… :(</p>
<p>번호를 이용하여 설명하겠습니다.</p>
<ol>
<li>현재 리소스 보다 한단계 아래에 리소스를 생성합니다. POST Method를 통해 해당 URI를 요청하면 sports 컬렉션에 알맞은 soccer 또는 baseball과 같은 도큐먼트 리소스를 생성합니다.</li>
<li>현재 리소스를 조회합니다. 보통 컬렉션 리소스를 조회하게되면 하위의 도큐먼트들의 목록과 아주 간단한 정보들을 가져옵니다.</li>
<li>현재 리소스를 조회 합니다. 도큐먼트 리소스를 조회하게되면 해당 도큐먼트에 대한 자세한 정보들을 가져옵니다.</li>
<li>현재 리소스를 수정합니다. soccer에 대한 정보를 수정하게 됩니다.</li>
<li>현재 리소스를 삭제합니다. DELETE Method를 이용하여 현재 URI를 호출하면 sports 컬렉션에서 soccer 도큐먼트가 삭제됩니다.</li>
</ol>
<p>※추가로 주목해볼 만한 Method는 <code>PATCH</code>입니다.
기존에 REST에 익숙하신분들은 수정(update)을 위한 Method는 <code>PUT</code>가 익숙하실 겁니다. 하지만 앞으로는 <code>PUT</code>대신 <code>PATCH</code>를 자주 써야할꺼 같아요. 자세한 설명은 <a href="http://weblog.rubyonrails.org/2012/2/26/edge-rails-patch-is-the-new-primary-http-method-for-updates/">Edge Rails: PATCH is the new primary HTTP method for updates</a>을 참조해주세요.</p>
<p><a name="responsive"></a></p>
<h3>반응형 웹에서의 REST</h3>
<p>요즘은 정말 다양한 장비들이 존재합니다. 크기 역시 다양합니다. 그래서 요즘 작은 화면의 기기로 포털사이트를 접속해보면 어느 형태로든 <code>m</code>이 붙은걸 볼수 있습니다. 아마 <code>mobile</code>에서 맨앞의 <code>m</code>인것같은데, 화면이 작은 장비에서는 800*600이 넘어가는 사이트를 돌아다니는건 정말 피곤한 일입니다. 그래서 작은 화면용 페이지가 필요한 이유입니다. 네, 여기까지는 좋습니다. 제가 이 부분에서 소개해드리려는 header는 <a href="http://tools.ietf.org/html/rfc2616#section-14.43">User-Agent</a>입니다. 그리고 결론적으로 말씀드리고 싶은 내용은 <code>http://m.remotty.com/abc</code> 또는 <code>http://www.remotty.com/m/abc</code>처럼 사용하지 말자 입니다.</p>
<p>한가지 예를 들어보겠습니다.</p>
<ol>
<li>철수가 안드로이드로 뉴스를 읽고있음</li>
<li>재미있는 기사 발견,</li>
<li>sns로 공유</li>
<li><code>http://m.remotty.com/fun</code> 공유됨.</li>
<li>영희가 이번에 새로산 신상 <a href="http://store.apple.com/kr/buy-mac/macbook-pro?product=ME294KH/A&step=config">15형 MacBook Pro Retina</a>을 가지고 sns 보고있음</li>
<li>철수가 공유한 링크(<code>http://m.remotty.com/fun</code>)클릭.</li>
<li>영희는 작은화면으로 웹서핑을 하고있는게 아닌데도 불구하고</li>
<li>모바일에 최적화된 화면으로 뉴스를 읽게됩니다.</li>
</ol>
<p>뭐가 문제인지 감이 오시나요? 이미 많은 웹사이트가 <code>User-Agent</code> header을 사용중입니다. <code>User-Agent</code> header을 적절히 파싱하여 화면이 작은 장비는 모바일에 최적화된 사이트로 이동(redirect)시켜주고 있습니다.</p>
<p>RESTFul한 웹사이트에서는 <code>User-Agent</code>를 이용하여 다른 곳으로 리다이렉트 시켜주는게 아니라 URI는 그대로이지만 화면만 장비에따라 알아서 최적화 되도록 설계해야합니다.</p>
<p>다시말해서 <code>http://www.remotty.com/info</code>와 <code>http://m.remotty.com/info</code>는 사실상 같은 정보를 보여주고 있지만 화면의 형태만 다를 뿐입니다. REST하게 설계할땐 리소스가 같다면 URI는 하나여야 합니다.</p>
<p><a name="i18n"></a></p>
<h3>I18n과 REST</h3>
<p>현재 많은 웹사이트들이 다국어를 지원하고있고, <code>http://www.remotty.com/ko/info</code>나 <code>http://en.remotty.com</code>등과 같이 언어마다 다른 URI를 운영중인 곳이 있습니다. 여기서 소개해드릴 것은 <a href="http://tools.ietf.org/search/rfc3282#section-3">Accept-Language</a> header입니다.</p>
<p>또 한번 예를 들어보겠습니다.</p>
<ol>
<li>한국인 철수가 뉴스를 읽음.</li>
<li>재미있는 기사발견,</li>
<li>sns로 공유</li>
<li><code>http://ko.remotty.com/fun</code> 공유됨.</li>
<li>remotty는 다국어가 아주 잘 지원되는 사이트임.</li>
<li>미국인 Cathy(캐씨)가 sns를 보고있음</li>
<li>캐씨는 미국인임에도 불구하고,</li>
<li>한국어로된 뉴스기사를 읽게됩니다.</li>
</ol>
<p>뭐가 문제인지 감이 오시나요? 다국어 지원을 <code>Accept-Language</code>에 맡긴다면 URI는 그대로인데, 사용자의 환경에 따라 알맞은 언어로 응답할 수 있습니다. 물론 <code>Accept-Language</code>만 가지고 다국어를 하면 조금 어색할 수 있을꺼 같습니다. 사용자가 원하는 언어를 설정하게하여 해당 언어를 세션 또는 쿠키 등에 저장하여 보여줄 언어를 선정할때 우선순위를 약간 조정하여 보여주는게 좋은 방법일꺼 같습니다.</p>
<p>지금 약간 이글의 <a href="#extension">확장자를 사용하지 말자</a>와 <a href="#responsive">반응형 웹에서의 REST</a>랑 약간 비슷한 느낌인데요, 모두 결론은 URI는 리소스를 식별하기 위해서 사용되었지, 리소스가 어떻게 보여지느냐는 별도의 header을 이용하여 처리하였습니다. 이 점을 생각하면서 다른 문제들도 좀더 REST하게 설계해야겠습니다.</p>
<p><a name="status"></a></p>
<h3>응답 상태 코드</h3>
<p><a href="http://tools.ietf.org/search/rfc2616#page-39">rfc2616</a>을 살펴보면 많은 종류의 상태코드가 존재합니다. 상태코드를 적절히 잘 사용하면 클라이언트에게 많은 정보를 줄 수 있습니다.</p>
<p><a name="statusSuccess"></a></p>
<h4>성공</h4>
<ul>
<li><a name="200"></a>200 – 클라이언트의 요청을 정상적으로 수행하였을때 사용합니다. 응답 바디(body)엔 요청과 관련된 내용을 넣어줍니다. 그리고 200의 응답 바디에 오류 내용을 전송하는데 사용해서는 안된다고 합니다. 오류가 났을땐 40x 응답 코드를 권장합니다.</li>
<li><a name="201"></a>201 – 클라이언트가 어떤 리소스 생성을 요청하였고, 해당 리소스가 성공적으로 생성되었을때 사용합니다.</li>
<li><a name="202"></a>202 – 클라이언트의 요청이 비동기적으로 처리될때 사용합니다. 응답 바디에 처리되기까지의 시간 등의 정보를 넣어주면 좋다고 합니다.</li>
<li><a name="204"></a>204 – 클라이언트의 요청응 정상적으로 수행하였을때 사용합니다. 200과 다른점은 204는 응답 바디가 없을때 사용합니다. 예를들어 DELETE와 같은 요청시에 사용합니다. 클라이언트의 리소스 삭제요청이 성공했지만 부가적으로 응답 바디에 넣어서 알려줄만한 정보가 하나도 없을땐 204를 사용합니다.</li>
</ul>
<p><a name="statusFail"></a></p>
<h4>실패</h4>
<ul>
<li><a name="400"></a>400 – 클라이언트의 요청이 부적절할때 사용합니다. 요청 실패시 가장 많이 사용될 상태코드로 예를들어 클라이언트에서 보낸 것들이 서버에서 유효성 검증(validation)을 통과하지 못하였을때 400으로 응답합니다. 응답 바디에 요청이 실패한 이유를 넣어줘야 합니다.</li>
<li><a name="401"></a>401 – 클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청했을때 사용하는 요청입니다. 예를들어 로그인(login)하지 않은 사용자가 로그인했을때에만 요청 가능한 리소스를 요청했을때 401을 응답합니다.</li>
<li><a name="403"></a>403 – 사용자 인증상태와 관계 없이 응답하고싶지 않은 리소스를 클라이언트가 요청했을때 사용합니다. 그러나 해당 응답코드 대신 400을 사용할 것을 권고합니다. 그 이유는 일단 403 응답이 왔다는것 자체는 해당 리소스가 존재한다는 뜻입니다. 응답하고싶지 않은 리소스는 존재 여부 조차 감추는게 보안상 좋기때문에 403을 응답해야할 요청에 대해선 그냥 400이나 404를 응답하는게 좋겠습니다.</li>
<li><a name="404"></a>404 – 클라이언트가 요청한 리소스가 존재 하지 않을때 사용하는 응답입니다.</li>
<li><a name="405"></a>405 – 클라이언트가 요청한 리소스에서는 사용 불가능한 Method를 이용했을때 사용하는 응답입니다. 예를들어 읽기전용 리소스에 DELETE Method를 사용했을때 405 응답을 하면 됩니다.</li>
</ul>
<p><a name="statusEtc"></a></p>
<h4>기타</h4>
<ul>
<li><a name="301"></a>301 – 클라이언트가 요청한 리소스에 대한 URI가 변경 되었을때 사용합니다. 응답시 <code>Location</code> header에 변경된 URI를 적어줘야 합니다.</li>
<li><a name="statusS500uccess"></a>500 – 서버에 뭔가 문제가 있을때 사용합니다.</li>
</ul>
<p><a href="http://www.hanbit.co.kr/ebook/look.html?isbn=9788979149456">마크 마세가 쓴 REST API 디자인 규칙</a>에 이런 말이 있네요.</p>
<blockquote><p>REST API는 부실한 HTTP 클라이언트에 부합하려는 그 어떤 타협도 해서는 안된다.</p></blockquote>
<p><a name="epilogue"></a></p>
<h3>마치며</h3>
<p>순서가 약간 뒤죽박죽 작성된 느낌이 있네요. 사실 저도 RESTFul한게 좋은건지 나쁜건지 뭔지 아직도 잘 모르는 상태로 작성하였는데, 한가지 확실한건 REST라는 개념(?)이 널리 퍼지고 많은 API들이 RESTFul하다면 REST에서 다루는 내용들은 따로 문서화도 필요없이 자연스레 좀더 체계적인 느낌으로 API를 사용할 수 있을꺼 같은 느낌이 듭니다. 아직 미완성된 글이라 생각합니다. 틀린 내용이나 이해되지 않는 내용이 있으시면 댓글이나 기타 편하신 방법을 통해 적극적으로 글을 완성해주시길 바랍니다.</p>
<p><a name="reference"></a></p>
<h3>참고자료</h3>
<ul>
<li><a href="http://www.hanbit.co.kr/ebook/look.html?isbn=9788979149456">일관성 있는 웹 서비스 인터페이스 설계를 위한 REST API 디자인 규칙</a></li>
<li><a href="http://spoqa.github.io/2012/02/27/rest-introduction.html">REST 아키텍처를 훌륭하게 적용하기 위한 몇 가지 디자인 팁</a></li>
<li><a href="http://spoqa.github.io/2013/06/11/more-restful-interface.html">RESTful API를 설계하기 위한 디자인 팁</a></li>
<li><a href="http://httpd.apache.org/docs/current/ko/content-negotiation.html">내용협상 (Content Negotiation)</a></li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[리모티하게 일하기 2]]></title>
<link href="http://remotty.github.io/blog/2014/01/24/rimotihage-ilhagi-2/"/>
<updated>2014-01-24T13:49:15+09:00</updated>
<id>http://remotty.github.io/blog/2014/01/24/rimotihage-ilhagi-2</id>
<content type="html"><![CDATA[<p>약 한달 전 <a href="http://remotty.github.io/blog/2013/12/10/remottyhage-ilhagi/">Remotty하게 일하기</a>라는 제목으로, Remotty 그룹의 일하는 방식에 대해 포스팅을 했었다.<br/>
포스트에서 소개한 방법대로 약 한달 가량 remote 방식으로 협업을 해보니, 불편한 점이 한두가지가 아니었다.</p>
<!--more-->
<p>나름 효율적으로 협업을 하기 위해, 각각의 활동에 최적화(?)된 도구를 선정하고 그것을 사용하기로 했었는데<br/>
가장 큰 문제는 <strong>사용해야 할 도구가 너무 많아 커뮤니케이션이 분산</strong>된다는 것이었다.</p>
<p>페이스북, 트렐로, 구글 드라이브, 에버노트…<br/>
모두 다 좋은 도구다. 잘만 활용한다면 좋은 커뮤니케이션 도구로 사용할 수 있다.<br/>
하지만 개발자들간의 협업에 있어서 소스코드가 제일 중요할 수 밖에 없고,<br/>
그 커뮤니케이션의 중심에 github가 있는 것은 당연지사.</p>
<p>결국 github로 돌아오게 되더라.<br/>
이슈 관리도, 일정 관리도, 대화도, 각종 문서 정리도, 대화도…<br/>
모든 커뮤니케이션을 github안에서 해결할 수 있는 방법을 찾게 되었다.</p>
<p>그래서 결론을 얘기하면, 현재는 아래와 같은 방식으로 협업을 하고 있다.</p>
<ul>
<li><p>태스크 관리<br/>
<del>트렐로</del> github 이슈 + <a href="https://waffle.io/">Waffle</a></p></li>
<li><p>문서 공유<br/>
<del>에버노트 or 구글 드라이브</del> github 위키</p></li>
<li><p>단체 코딩<br/>
MadEye</p></li>
<li><p>소스 관리<br/>
github</p></li>
<li><p>잡다구리한 이야기들 + 각종 대화 & 논의 + 그 외 모든 의사소통<br/>
<del>페이스북 포스트 or 메신저</del> <a href="https://www.hipchat.com">HipChat</a></p></li>
<li><p>기타 파일 공유<br/>
<del>드롭박스</del> HipChat으로 전달. 파일 관리는 따로 안함.<br/>
정말 지속적으로 관리할 필요가 있는 파일이 있다면 github에 올려도 될 것 같음</p></li>
<li><p>오프라인 모임</p>
<ul>
<li>공식 모임<br/>
월 1회<br/>
지난 한달간 진행상황 점검 & 향후 한달 계획 수립<br/>
각종 의사결정 및 이슈 정리</li>
<li>비공식 모임<br/>
매주 토요일<br/>
그냥 모여서 다 같이 코딩</li>
</ul>
</li>
</ul>
<p>여기 <a href="http://remotty.github.io/blog/2013/12/10/remottyhage-ilhagi/">이전 포스트</a>에 소개되지 않았던 새로운 도구가 등장한다.<br/>
바로 <a href="https://waffle.io/">Waffle</a>과 <a href="https://www.hipchat.com">HipChat</a>이다.
이 두가지를 한번 소개해본다.</p>
<h3>Waffle</h3>
<p>쉽게 말해서 github의 이슈들을 dashboard 형태로 보여주는 도구이다.<br/>
그것이 전부이다.<br/>
github 이슈는 단순히 목록 형태로 쭉 펼쳐져서 보이기 때문에,<br/>
원하는 것들을 필터링 해서 보거나 한눈에 dashboard 형태로 보기가 어렵다.<br/>
그러한 불편함을 해소해주는 도구가 바로 Waffle이다.<br/>
눈에 보기 쉽게 Column을 만들고 그 안에 github에 등록된 이슈들이 list 형태로 뿌려진다.<br/>
얼핏 보기엔 trello와 비슷해 보인다.<br/>
github의 이슈들이 trello의 card 형태로 나타나고, drag&drop으로 쉽게 상태를 변경할 수 있다.<br/>
Waffle에서 생성한 Column은 github 이슈의 라벨로 나타난다.<br/>
Waffle에서도 이슈를 등록할 수 있고, 당연히 github 이슈에도 등록이 된다.<br/>
백날 얘기해봤자 머리속의 상상만으로는 잘 이해가 안된다. 아래 사진을 보면 딱 이해가 될 것이다.</p>
<p><img src="http://remotty.github.io/images/waffle.png" title="waffle" alt="waffle" /></p>
<h3>HipChat</h3>
<p>기본적으로 메신저는 실시간성이다.<br/>
온라인상의 누군가에게 메시지를 보내고 그것을 본 누군가는 응답을 한다. 이것이 메신저의 기본 개념.<br/>
하지만 단체 채팅의 경우는 상황이 좀 다르다.<br/>
대화가 오고 갈때 온라인상에 없었던 사용자는 그 대화에 참여할 수 없게 되고 그때 오고 갔던 대화의 내용들은 놓치게 된다.<br/>
물론 스크롤을 쭉~ 올려서 찾아서 읽으면 된다.<br/>
당연히 그렇게 필요한 사람이 내가 놓친 내용을 꼼꼼히 스스로 찾아 읽으면 되지만, 잘 되지 않는다.<br/>
그리고 지난 대화들을 찾아서 본다 하더라도 이미 마무리 된 대화를 또다시 개진하려면 좀 뒷북치는 느낌이다. ;;<br/>
물론 하면 되지만, 대부분의 메신저 도구들은 실시간성에 UI가 맞추어져 있다.</p>
<p>그렇다. 우리에게 필요한 것은 바로 <strong>비동기 채팅</strong>이다.<br/>
비동기 채팅이란, 한마디로 <strong>“로그를 읽는다”</strong>라는 개념이다. <strong>대화의 기록</strong>을 보고 자신의 생각을 그냥 얘기하면 된다.<br/>
IRC가 바로 이러한 비동기 채팅에 적합한 도구이다. 하지만 왠지 irc는 말만 들어도 겁이 난다.(왜일까… ㅡ,.ㅡ;;)<br/>
이러한 용도로 최적화 된 툴이 바로 HipChat이다.</p>
<p>HipChat은 개발자들에게 좀 특화된 메신저 도구여서, 대화창에 각종 코드도 쓸 수 있다.<br/>
“/code”라고 prefix를 붙히면, 뒤에 따라오는 코드는 포맷팅이 되어 읽기 쉽게 나타난다.</p>
<p>뿐만 아니라 github와도 연동을 시킬 수 있어서, github에서 일어나는 모든 event를 hipchat에서 받을 수 있다.<br/>
hipchat의 api가 공개되어 있어서, github외에 다른 이벤트들도 hipchat에 전달하도록 구현할 수 있다.<br/>
여러 환경에서 활용 가능하도록, 각 언어별로 library를 제공하고 있다.(참고: <a href="https://www.hipchat.com/docs/api/libraries">HipChat Libraries & Plugins</a>)<br/>
ruby 코드로 2줄이면 hipchat에 message를 날릴 수 있다.</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>client = HipChat::Client.new(api_token)
</span><span class='line'>client['my room'].send('username', 'I talk')</span></code></pre></td></tr></table></div></figure>
<p>HipChat이 제공하는 또다른 killer 기능이 있다. 바로 notify 기능이다.<br/>
대화를 할때 ‘@’ 표시와 함께 대상자에 대한 mention을 표기할 수 있는데, @로 mention을 날리면 상대방에게 notify가 간다.<br/>
상대방이 온라인이 아니더라도 mention을 받게 되면 notify가 오게 되고, 그때 대화에 동참하면 된다.<br/>
그리고 notify는 메일로도 전송되기 때문에, 내가 없는 자리에서 나와 관련된 중요한 대화가 오고 갔는지를 알 수 있다.<br/>
내가 없는 자리에서 오고 갔던 대화 히스토리에 나에게 mention 표시가 되어 있는 전/후의 내용을 좀 더 주의 깊게 보면 된다.<br/>
mention은 @all 이런 식으로 사용할 수도 있다. 당연히 모든 멤버에게 mention을 날린다는 의미다.<br/>
대화 중, 특정 누군가에게 또는 모두에게 공유해야 할 내용이 있을 때, @로 mention을 날리면 된다.</p>
<p>비동기 채팅에 notify 기능이 합쳐지고, 코드에 대한 마크업 기능까지…<br/>
remote로 일하는 개발 그룹에 꼭 필요한 도구이다!</p>
<p>하지만 단점이 있다.<br/>
5명 이상인 경우엔 유료라는 것. (매월 1명당 2$씩)<br/>
한달에 2$면 커피한잔 가격도 안된다.<br/>
효과적인 커뮤니케이션을 위해 한달에 커피 한잔 정도는 절약하는건 어떨까? ^^</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[active_model_serializers 젬 사용하기]]></title>
<link href="http://remotty.github.io/blog/2013/12/31/active-model-serializers/"/>
<updated>2013-12-31T19:51:34+09:00</updated>
<id>http://remotty.github.io/blog/2013/12/31/active-model-serializers</id>
<content type="html"><![CDATA[<p><code>active_model_serializers</code>젬은 레일스 API 를 작성할 때 JSON 데이터를 만들기 위해 추천되는 젬입니다.</p>
<h1>설치</h1>
<p>Gemfile 에 추가하고 bundle install 합니다.</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>gem <span class="s1">'active_model_serializers'</span>
</span></code></pre></td></tr></table></div></figure>
<!--more-->
<h1>Serializer 생성하기</h1>
<p>이후부터 <code>scaffolding</code>이나 <code>model generator</code>를 사용하여 특정 모델을 생성하면 자동으로 <code>serializer</code>가 만들어 집니다.</p>
<p>이미 만들어진 모델에 대해서는 아래와 같이 직접 <code>serializer</code>를 생성할 수 있습니다. 여기서는 <code>Post</code> 모델에 대한 <code>serializer</code>를 생성하는 예를 들었습니다.</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>rails g serializer post
</span></code></pre></td></tr></table></div></figure>
<p>이제 <code>app/serializers/post_serializer.rb</code>에서 <code>Post</code> 모델에 대한 <code>serializer</code>를 볼 수 있게 됩니다.</p>
<h1>render :json</h1>
<p>컨트롤러에서 <code>render :json</code>을 사용하면, 우선적으로 해당 객체에 대한 <code>serializer</code>를 찾아보고 있으면 해당 <code>serializer</code>를 사용하게 됩니다.</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">PostsController</span> <span class="o"><</span> <span class="no">ApplicationController</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">show</span>
</span><span class='line'> <span class="vi">@post</span> <span class="o">=</span> <span class="no">Post</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">params</span><span class="o">[</span><span class="ss">:id</span><span class="o">]</span><span class="p">)</span>
</span><span class='line'> <span class="n">render</span> <span class="ss">json</span><span class="p">:</span> <span class="vi">@post</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<h1>배열</h1>
<p>배열에 대해서도 <code>render :json</code>을 사용할 수 있습니다.</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">PostSerializer</span> <span class="o"><</span> <span class="ss">ActiveModel</span><span class="p">:</span><span class="ss">:Serializer</span>
</span><span class='line'> <span class="n">attributes</span> <span class="ss">:title</span><span class="p">,</span> <span class="ss">:body</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">PostsController</span> <span class="o"><</span> <span class="no">ApplicationController</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">index</span>
</span><span class='line'> <span class="vi">@posts</span> <span class="o">=</span> <span class="no">Post</span><span class="o">.</span><span class="n">all</span>
</span><span class='line'> <span class="n">render</span> <span class="ss">json</span><span class="p">:</span> <span class="vi">@posts</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>렌더링되는 결과는 아래와 같습니다.</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="p">{</span>
</span><span class='line'> <span class="s2">"posts"</span><span class="o">:</span>
</span><span class='line'> <span class="p">[</span>
</span><span class='line'> <span class="p">{</span> <span class="s2">"title"</span><span class="o">:</span> <span class="s2">"Post 1"</span><span class="p">,</span> <span class="s2">"body"</span><span class="o">:</span> <span class="s2">"Hello!"</span> <span class="p">},</span>
</span><span class='line'> <span class="p">{</span> <span class="s2">"title"</span><span class="o">:</span> <span class="s2">"Post 2"</span><span class="p">,</span> <span class="s2">"body"</span><span class="o">:</span> <span class="s2">"Goodbye!"</span> <span class="p">}</span>
</span><span class='line'> <span class="p">]</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>디폴트로 컨트롤러의 이름이 루트 엘리먼트의 이름이 됩니다. 즉, <code>PostsController</code>는 <code>posts</code>라는 루트노드명을 만들어 줍니다. 또한 아래와 같이 루트노드명을 변경할 수도 있습니다.</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">render</span> <span class="ss">json</span><span class="p">:</span> <span class="vi">@posts</span><span class="p">,</span> <span class="ss">root</span><span class="p">:</span> <span class="s2">"some_posts"</span>
</span></code></pre></td></tr></table></div></figure>
<h1>루트 엘리먼트를 없애는 방법 4가지</h1>
<ul>
<li><p>모든 클래스에 대해서 루트 엘리먼트를 사용하지 않는 방법</p>
<p>initializer 파일을 새로 만들어 아래와 같이 추가해 줍니다.</p></li>
</ul>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'> <span class="c1"># Disable for all serializers (except ArraySerializer)</span>
</span><span class='line'> <span class="ss">ActiveModel</span><span class="p">:</span><span class="ss">:Serializer</span><span class="o">.</span><span class="n">root</span> <span class="o">=</span> <span class="kp">false</span>
</span><span class='line'>
</span><span class='line'> <span class="c1"># Disable for ArraySerializer</span>
</span><span class='line'> <span class="ss">ActiveModel</span><span class="p">:</span><span class="ss">:ArraySerializer</span><span class="o">.</span><span class="n">root</span> <span class="o">=</span> <span class="kp">false</span>
</span><span class='line'>
</span></code></pre></td></tr></table></div></figure>
<ul>
<li>컨트롤러에서 render 옵션으로 지정하는 방법</li>
</ul>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">render</span> <span class="ss">json</span><span class="p">:</span> <span class="vi">@posts</span><span class="p">,</span> <span class="ss">root</span><span class="p">:</span> <span class="kp">false</span>
</span></code></pre></td></tr></table></div></figure>
<ul>
<li>Serializer를 상속받는 방법</li>
</ul>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">CustomArraySerializer</span> <span class="o"><</span> <span class="ss">ActiveModel</span><span class="p">:</span><span class="ss">:ArraySerializer</span>
</span><span class='line'> <span class="nb">self</span><span class="o">.</span><span class="n">root</span> <span class="o">=</span> <span class="kp">false</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># controller:</span>
</span><span class='line'><span class="n">render</span> <span class="ss">json</span><span class="p">:</span> <span class="vi">@posts</span><span class="p">,</span> <span class="ss">serializer</span><span class="p">:</span> <span class="no">CustomArraySerializer</span>
</span></code></pre></td></tr></table></div></figure>
<ul>
<li>컨트로러에 <code>default_serializer_options</code> 메소드를 정의하는 방법</li>
</ul>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">default_serializer_options</span>
</span><span class='line'> <span class="p">{</span>
</span><span class='line'> <span class="ss">root</span><span class="p">:</span> <span class="kp">false</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<h1>Attributes와 Associations</h1>
<p>serializer 클래스에서는 속성과 관계를 지정할 수 있습니다.</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">PostSerializer</span> <span class="o"><</span> <span class="ss">ActiveModel</span><span class="p">:</span><span class="ss">:Serializer</span>
</span><span class='line'> <span class="n">attributes</span> <span class="ss">:id</span><span class="p">,</span> <span class="ss">:title</span><span class="p">,</span> <span class="ss">:body</span>
</span><span class='line'> <span class="n">has_many</span> <span class="ss">:comments</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<h1>Attributes</h1>
<p>attributes로 명시한 속성들에 대해서 serializer는 <code>render :json</code> 호출시에 넘겨준 액티브레코드 객체에 대해서 해당 속성들을 찾아보게 됩니다. 이 때 serializer는, <code>ActiveRecord</code> 객체가 속성을 조회하기 위해서는 사용하는 <code>read_attribute_for_serialization</code> 메소드를 이용하게 됩니다.</p>
<p>특정 객체에 대한 속성을 조회해 보기 전에, serializer는 해당 속성과 같은 이름의 메소드가 정의되어 있는지를 알아 보고 있다면 모델 속성을 포함하기 전에 해당 메소드의 결과를 속성으로 포함하게 됩니다.</p>
<p>예를 들면,</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">PersonSerializer</span> <span class="o"><</span> <span class="ss">ActiveModel</span><span class="p">:</span><span class="ss">:Serializer</span>
</span><span class='line'> <span class="n">attributes</span> <span class="ss">:first_name</span><span class="p">,</span> <span class="ss">:last_name</span><span class="p">,</span> <span class="ss">:full_name</span>
</span><span class='line'>
</span><span class='line'> <span class="k">def</span> <span class="nf">full_name</span>
</span><span class='line'> <span class="s2">"</span><span class="si">#{</span><span class="n">object</span><span class="o">.</span><span class="n">first_name</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">object</span><span class="o">.</span><span class="n">last_name</span><span class="si">}</span><span class="s2">"</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>serializer 메소드 내에서 객체는 <code>object</code>로써 접근하게 됩니다.
따라서 속성명이 <code>object</code> 라는 이름을 가질 경우 그 이름이 감춰지게 되므로 이 때는 <code>object.object</code>로써 접근할 수 있습니다. 예를 들면,</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">VersionSerializer</span> <span class="o"><</span> <span class="ss">ActiveModel</span><span class="p">:</span><span class="ss">:Serializer</span>
</span><span class='line'> <span class="n">attribute</span> <span class="ss">:version_object</span><span class="p">,</span> <span class="ss">key</span><span class="p">:</span> <span class="ss">:object</span>
</span><span class='line'>
</span><span class='line'> <span class="k">def</span> <span class="nf">version_object</span>
</span><span class='line'> <span class="n">object</span><span class="o">.</span><span class="n">object</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>