2024 Advent-of-spin Challenge 2
14 Dec 2024 | Etc이 포스트는 advent-of-spin에 업로드 된 Challenge 2에 대해서 진행했던 내용을 정리한 포스트 입니다.
Rust 언어로 진행하였으며 이 포스트에 게시된 소스코드는 Github 에서 확인할 수 있습니다.
Spec
- Spin 3.0에서 추가된
Component Dependencies
기능을 사용하여 naughty-or-nice 점수 매기는 기능 구현하기 /naughty-or-nice.html
에 특정 사람이름을 입력하고 점수를 확인할 수 있는 API가 추가된 프론트엔드 추가하기/api/naughty-or-nice
path에서 GET method 구현하기- GET
/api/naughty-or-nice/:name
: name에 해당하는 naughty-or-nice 점수 출력{ "name": "John Doe", "score": 99 }
- response header에
Content-Type: application/json
- GET
Work
이 Challenge도 Challenge 1과 마찬가지로 static page와 api가 구현된 wasm component를 사용하기 위해 challenge 1에서 만들어놓은 프로젝트를 기반으로 사용하려고 합니다.
우선 프론트엔드 부분을 구현하기 위해 assets/naughty-or-nice.html
파일을 생성합니다.
assets/naughty-or-nice.html
경로에 GET 요청을 보내면 아래와 같은 응답을 받을 수 있도록 구현합니다.
<!DOCTYPE html>
<html>
<head>
<title>Naughty or Nice</title>
</head>
<body>
<h1>Naughty or Nice Checker</h1>
<input type="text" id="nameInput" placeholder="Enter name">
<button onclick="checkScore()">Check Score</button>
<p id="result"></p>
<script>
async function checkScore() {
const name = document.getElementById('nameInput').value;
const response = await fetch(`/api/naughty-or-nice/${encodeURIComponent(name)}`);
const data = await response.json();
document.getElementById('result').textContent = `${data.name} is scored: ${data.score}`;
}
</script>
</body>
</html>
이번에는 rust 코드를 작성하기 전에 Component Dependencies
기능을 사용하여 score를 출력하는 기능이 포함된 wasm component를 추가해보겠습니다.
우리는 이 컴포넌트를 구현하기 위해 componentize-js
와 jco
를 사용할 것입니다.
우선 이 두가지 패키지를 설치합니다
npm install -g @bytecodealliance/componentize-js @bytecodealliance/jco
우리는 JS/TS 코드를 wasm으로 빌드하기 위해 위 두가지 패키지를 사용하여 구현해 보겠습니다.
우선 js 코드를 작성합니다. scoring.js
파일을 생성하고 아래와 같이 작성합니다.
/**
* This module is the JS implementation of the `reverser` WIT world
*/
/**
* The Javascript export below represents the export of the `reverse` interface,
* which which contains `reverse-string` as it's primary exported function.
*/
export const scoring = {
/**
* This Javascript will be interpreted by `jco` and turned into a
* WebAssembly binary with a single export (this `reverse` function).
*/
scoring(name) {
const randomFactor = Math.floor(Math.random() * 100);
return Math.max(1, Math.min(randomFactor, 99));
},
};
그리고 scoring.wit
파일을 생성하고 아래와 같이 작성합니다.
package local:scoring;
interface scoring {
scoring: func(name: string) -> u32;
}
world component {
export scoring;
}
위 두가지 파일을 이용하여 wasm 파일을 생성합니다.
jco componentize scoring.js -w scoring.wit -o scoring.component.wasm
그렇게 되면 scoring.component.wasm
파일이 생성됩니다.
이제 이 wasm 파일을 spin 프로젝트에 추가해야 합니다.
이를 위해서 spin deps generate-bindings
커맨드를 사용하여 wasm 파일에 대한 binding을 생성해 주어야 하는데 이를 위해서 spin plugin을 설치해 주어야 합니다.
- https://github.com/fermyon/spin-deps-plugin/tree/main?tab=readme-ov-file#installation
설치가 완료 되었다면 아래 명령어를 사용하여 binding을 생성합니다.
spin deps generate-bindings -L rust -o src/bindings -c challenge2
위 과정이 정상적으로 수행 되엇다면 src/bindings
경로에 파일이 생성된 것을 확인할 수 있습니다.
이제 이 파일을 이용하여 rust 코드를 작성해보겠습니다.
src/lib.rs
에 GET을 처리하기 위한 로직을 구현합니다.
use serde::{Deserialize, Serialize};
use spin_sdk::http::Method;
use spin_sdk::http::{IntoResponse, Request, Response};
use spin_sdk::http_component;
mod bindings;
#[derive(Debug, Serialize, Deserialize)]
struct NaughtyOrNice {
name: String,
score: u32,
}
#[http_component]
fn handle_request(req: Request) -> anyhow::Result<impl IntoResponse> {
println!("Received request: {:?}", req.method());
let (status, body) = match *req.method() {
Method::Get => {
println!("GET request received");
let path = req.uri();
let parts: Vec<&str> = path.split('/').collect();
let name = parts[5];
let name = urlencoding::decode(name).unwrap();
let score = bindings::deps::local::scoring::scoring::scoring(&name);
println!("param: {:?}", name);
let json_body = NaughtyOrNice {
name: name.clone().to_string(),
score,
};
(200, serde_json::to_vec(&json_body).unwrap())
}
_ => (404, Vec::new()),
};
Ok(Response::builder()
.status(status)
.header("content-type", "application/json")
.body(body)
.build())
}
-
spin build
로 빌드를 수행합니다. -
spin up
으로 로컬에서 실행이 가능합니다. - curl을 사용하여 가볍게 테스트가 가능합니다.
-
GET
curl http://127.0.0.1:3000/api/naughty-or-nice/abc
-
-
아래 명령어로 제출 전 테스트가 가능합니다.
hurl --test test.hurl