이 문서는
DartWatch 의 번역 문서 입니다.^_^
Dart를 Client(Browser상에서)와 Server에서 사용할 수 있는지에 대해 물어보는 글 들을 메일링 리스트와 Stack Overflow에서 심심치 않게 볼 수 있습니다. 그래서 이 번 포스트에서는 예제를 통해 어떻게 하는 것인지 보여드리고자 합니다.
Server Side
첫번째로 Server Side에 대해서 다루고자 합니다. Dart는 Server에서 Python, Ruby그리고 Node.js와 같은 Server Side Script들 처럼 사용할 수 있습니다. Windows에서는 dart.exe <실행.dart> 방식으로 사용 됩니다. 다음 예제를 보시겠습니다.
//MyScript.dart
main() => print("Hello Dart");
그리고, 이것을 Console 에서 "dart.exe MyScript.dart"을 실행 시키면 다음과 같은 결과물을 볼 수 있습니다.
Hello Dart
그럼에도 불구하고 우리는 좀 더 유용한 것을 원합니다. 그래서 저는 다음 Diagram을 통해 어떻게 어플리케이션을 만들 수 있는지 계획을 세웠습니다.
Server Side Component는 2가지 행동을 실행 할 것입니다.
1. Http Protocol을 통해서 브라우저에게 다음 static 파일들을 전송할 것입니다.
- MyApp.html
- MyApp.dart
- MyApp.dart.js
2. 나머지 GET Http Request에 대해서는 요청된 이름을 가진 JSON 데이터를 전송합니다. 예를 들면 http://localhost:8080/helloWorld(/helloWorld가 GET됩니다.)를 호출 하게 되면, 다음과 같은 JSON 데이터가 전송 됩니다.
{"get":"helloWorld"}
이를 위해서 우리는 dart:io Library를 통해 HTTPServer를 이용해야 합니다. 모든 Dart 앱들은 main() 함수를 통해 시작이 되므로, MyServer.dart라는 화일을 다음과 같이 구성해 보겠습니다.
#import("dart:io"); // dart:io Library를 가져옵니다.
main() {
HttpServer server = new HttpServer(); // Server를 생성합니다.
serve.listen("127.0.0.1", 8080); // Listening을 시작합니다.
}
Server는 "dart.exe MyServer.dart"를 통해 실행 시킬 수 있습니다. 아직 이것은 아무 동작도 되지 않습니다. 그래서 우리는 Request에 반응 할 수 있는 Callback함수를 추가해야 합니다. 처음엔 기본적인 Response를 추가하겠습니다. 이 함수는 HttpRequest를 통해 URL을 분석하여 JSON 데이터를 생성하여 HttpResponse를 통해 데이터를 내려주는 것입니다. Callback은 defaultRequestHandler 속성을 통해서 할당 합니다.
#import("dart:io"); // dart:io Library를 가져옵니다.
#import("dart:json"); //json Library를 가져옵니다.
main() {
HttpServer server = new HttpServer(); // Server를 생성합니다.
server.defaultRequestHandler = defaultHandler; // Handle 함수를 할당 합니다.(하단에 있습니다)
serve.listen("127.0.0.1", 8080); // Listening을 시작합니다.
print("http://127.0.0.1:8080 서버가 활성화 되었습니다");
}
defaultHandler(HttpRequest req, HttpResponse res) {
Map data = new Map(); // Response를 위한 Map을 생성합니다.
print("${req.path}가 요청 되었습니다");
data["get"] == req.path; // 요청된 Path를 data에 담습니다.
String responseData = JSON.stringify(data); // map을 JSON으로 변경 합니다.
res.outputStream.writeString(responseData); // Client 에게 응답을 합니다.
res.outputStream.close(); // 응답을 닫습니다.
}
이제 Script를 실행 하고, 브라우저에 http://localhost:8080/hello를 입력하게 된다면 JSON데이터를 받을 수 있습니다.
두 번째로 실행 할 것은 Static파일 제공하기 입니다. 1회 요청에 3개 파일을 Load하고, 그 데이터를 응답하게 하는 방법을 알아보도록 하겠습니다. MyApp.html을 요청 받고, Browser에 정상적으로 데이터를 보내는 예제를 만들어 보도록 하겠습니다.
#import("dart:io"); // dart:io Library를 가져옵니다.
#import("dart:json"); //json Library를 가져옵니다.
main() {
HttpServer server = new HttpServer(); // Server를 생성합니다.
server.addRequestHandler(matchMyApp, myAppHandler); // 만약에 "myApp"로 시작하는 요청이 있으면 Handle합니다.
server.defaultRequestHandler = defaultHandler; // Handle 함수를 할당 합니다.(하단에 있습니다)
serve.listen("127.0.0.1", 8080); // Listening을 시작합니다.
print("http://127.0.0.1:8080 서버가 활성화 되었습니다");
}
defaultHandler(HttpRequest req, HttpResponse res) {
Map data = new Map(); // Response를 위한 Map을 생성합니다.
print("${req.path}가 요청 되었습니다");
data["get"] == req.path; // 요청된 Path를 data에 담습니다.
String responseData = JSON.stringify(data); // map을 JSON으로 변경 합니다.
res.outputStream.writeString(responseData); // Client 에게 응답을 합니다.
res.outputStream.close(); // 응답을 닫습니다.
}
bool matchMyApp(HttpRequest req){
bool result = req.path.startsWith("/MyApp"); // MyApp으로 시작 되면
print("MyApp과 일치여부 : $result");
return result;
}
// 파일을 열고 Client에게 전송한다.
void myAppHandler(HttpRequest req, HttpResponse res) {
File file = new File(".${req.path}"); // 요청한 파일을 가져옵니다. 예): ./MyApp.html
file.openInputStream().pipe(res.outputStream); // 요청에 응답합니다.
}
이제 Server를 돌리게 되면, Client가 MyApp.html을 호출 시 정상적으로 응답해줄 수 있습니다.(지금은 Editor 마법사에 의해 Dart 앱이 만들어질 것입니다.)
GitHub에서 이 파일을 다운로드 받고 실행 하신 후, http://localhost:8080/MyApp.html 혹은 http://localhost:8080/helloWorld를 실행해보시기 바랍니다.
(이것은 에디터 빌드넘버 7232 에서 안정적으로 동작합니다.)
Client Side Dart...
Client Side의 Dart를 시작해봅시다. 우선 Editor에서 New > Web Application으로 예제 앱을 만들어 봅니다.( Server Side Dart에서 호출이 될 수 있도록 MyApp이라고 이름을 설정합니다.)
Editor는 MyApp.dart와 MyApp.html 파일을 생성할 것입니다.MyApp.dart는 최초에 다음과 같을 것입니다.
#import('dart:html');
class MyApp{
MyApp(){
}
void run() {
write("Hello World!");
}
void write(String message) {
// HTML library는 "document" 전역 변수를 정의 합니다.
document.query('#status').innerHTML = message;
}
}
void main(){
new MuApp().run(); // Class의 instance를 생성하고, run함수를 호출 합니다.
// TODO : ui element를 이곳에 더 추가합니다.
}
Editor에서 "Tools > Generate Javascript"를 선택 하면 MyApp.dart.js 파일을 생성할 수 있습니다. HTML 파일을 살펴보면, Dartium에서는 자동으로 MyApp.dart 파일을 Load할 수 있도록 링크가 걸려 있을 것입니다. 그리고, 이 HTML파일은 Dartium이 아닌 브라우저를 위해서 MyApp.dart.js를 Load할 수 있도록 되어있습니다.
이 파일들은 MyServer.dart와 같은 폴더에 위치 되어야 합니다. 다시 한번 dart.exe를 이용해 MyServer.dart를 실행 시키고, http://127.0.0.1:8080/MyApp.html 을 요청 해보면 정상적으로 동작 됨을 볼 수 있습니다.
MyApp.dart를 좀 더 개선해보기로 하겠습니다. UI Element들을 더 추가하고, XMLHttpRequest(XHR)을 이용하여 Server Side에서 응답하는 JSON데이터를 받아보는 함수를 만들어보도록 하겠습니다.
이 함수는 Textbox, Button 그리고 서버에서 응답하는 데이터를 표시 할 수 있도록 Span Tag를 추가 할 것입니다. 그리고, Button을 클릭하면 Textbox에 입력된 URL에 XMLHttpRequest 객체를 이용하여 "GET"요청을 실행 할 것입니다. 예를 들어, "HelloWorld"를 TextBox에 입력 하고 Button을 클릭하게 되면 "http://127.0.0.1:8080/HelloWorld"에 요청하고 해당 JSON데이터로 응답할 것입니다. 아마도 {"get":"HelloWorld"}가 될 것입니다.
코드로 표현 해보도록 하겠습니다.
MyApp.dart를 수정 한 후, 다시 한번 Javascript 생성을 해주시기 바랍니다.
여기까지의 코드는
GitHub에서 받아 볼 수 있습니다. 총 4개의 파일로 구성 되어있습니다.(MyServer.dart, MyApp.html, MyApp.dart, MyApp.dart.js)
간단히 이 파일들을 한 폴더 안에 위치 시키고, 다음 명령어를 내려보세요.
path/to/dart.exe MyServer.dart
그 이후, Daritum 혹은 브라우저로 다음 URL을 실행 해보세요.
http://127.0.0.1:8080/MyApp.html
Cross Origin에러가 발생 되었다면, XMLHttpRequest가 다른 서버에서 호출하고 있다는 거을 뜻합니다. 서버가 http://127.0.0.1:8080 인지 재확인 해주시기 바랍니다.
만약에 문제가 없다면 다음과 같은 화면을 보실 수 있게 됩니다.
여러분이 Dart를 Client Side와 Server Side에서 어떻게 사용하는지 이해되었기를 희망합니다.
이 Server Side Implementation은 믿을 수 없을 정도로 기초적입니다. 어떠한 Http Header를 제공하지 않습니다. 예를 들어, MyApp이라는 것만 골라내는 코드를 만들기는 상당히 어렵습니다. 여러분들이 한 번 도전 해보시기 바랍니다.
비록 이 블로그에서는 Dart를 Client Side와 Server Side에서 동시에 사용하고 있습니다만, 여러분들은 다른 언어로 만들어 볼 수 있습니다. 예로, Server Side Dart + Client Side Flash 혹은 Server Side Ruby + Client Side Dart 등등이 되겠습니다.
JSON을 다루는 것을 더 알기 원한다면, 이
문서를 참조 해주세요.