Compare commits
3 Commits
ed8f93d7d0
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| b8ae633ed5 | |||
| ea690f0479 | |||
| fc79f5c579 |
@ -1,7 +1,7 @@
|
|||||||
# FairHopper JavaScript SDK
|
# FairHopper JavaScript SDK
|
||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
- Node 1.16+
|
- Node 18+
|
||||||
|
|
||||||
## Running demo
|
## Running demo
|
||||||
|
|
||||||
|
|||||||
@ -138,47 +138,6 @@ class FairHopper {
|
|||||||
}
|
}
|
||||||
return await r.json();
|
return await r.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
async getProducts() {
|
|
||||||
const r = await fetch(this.formatUrl("/products"), {
|
|
||||||
headers: this.defaultHeaders,
|
|
||||||
});
|
|
||||||
return await r.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
async getProduct(productId) {
|
|
||||||
const r = await fetch(this.formatUrl(`/products/${productId}`), {
|
|
||||||
headers: this.defaultHeaders,
|
|
||||||
});
|
|
||||||
switch (r.status) {
|
|
||||||
case 422:
|
|
||||||
throw new ValidationError();
|
|
||||||
}
|
|
||||||
return await r.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
async purchaseProduct(playerId, productId) {
|
|
||||||
const url = this.formatUrl(`/player/${playerId}/product/purchase`);
|
|
||||||
const postData = {
|
|
||||||
product_id: productId,
|
|
||||||
};
|
|
||||||
const r = await fetch(url, {
|
|
||||||
method: "post",
|
|
||||||
headers: this.defaultHeaders,
|
|
||||||
body: JSON.stringify(postData),
|
|
||||||
});
|
|
||||||
switch (r.status) {
|
|
||||||
case 403:
|
|
||||||
throw new PlayerInactiveError();
|
|
||||||
case 404:
|
|
||||||
throw new PlayerNotFoundError();
|
|
||||||
case 409:
|
|
||||||
throw new PositionError();
|
|
||||||
case 422:
|
|
||||||
throw new ValidationError();
|
|
||||||
}
|
|
||||||
return await r.json();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@ -5,6 +5,8 @@ Requirements:
|
|||||||
|
|
||||||
## Setting up environment
|
## Setting up environment
|
||||||
|
|
||||||
|
### Recommended: Using Poetry
|
||||||
|
|
||||||
Project uses [Poetry](https://python-poetry.org), ultimate dependency management software for Python.
|
Project uses [Poetry](https://python-poetry.org), ultimate dependency management software for Python.
|
||||||
|
|
||||||
Install Poetry:
|
Install Poetry:
|
||||||
@ -17,6 +19,23 @@ Install virtual environment:
|
|||||||
poetry install
|
poetry install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Simple: Using virtualenv
|
||||||
|
|
||||||
|
Create virtual environment:
|
||||||
|
```sh
|
||||||
|
virtualenv .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Activate virtual environment:
|
||||||
|
```sh
|
||||||
|
source .env/bin/activate
|
||||||
|
```
|
||||||
|
|
||||||
|
Install required dependencies:
|
||||||
|
```sh
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
## Running demo
|
## Running demo
|
||||||
|
|
||||||
Check `demo.py` for usage example.
|
Check `demo.py` for usage example.
|
||||||
@ -29,7 +48,15 @@ FAIRHOPPER_HOST = "http://127.0.0.1:8010"
|
|||||||
|
|
||||||
Activate environment and run example:
|
Activate environment and run example:
|
||||||
|
|
||||||
|
### Poetry
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
poetry shell
|
poetry shell
|
||||||
python demo.py
|
python demo.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Virtualenv
|
||||||
|
```sh
|
||||||
|
source .env/bin/activate
|
||||||
|
python demo.py
|
||||||
|
```
|
||||||
|
|||||||
@ -1,28 +1,35 @@
|
|||||||
from typing import List, Optional
|
|
||||||
from pydantic import BaseModel
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class BaseError(Exception):
|
class BaseError(Exception):
|
||||||
...
|
detail: str = "BaseError"
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.detail
|
||||||
|
|
||||||
|
|
||||||
class PositionError(BaseError):
|
class PositionError(BaseError):
|
||||||
...
|
detail = "Invalid position"
|
||||||
|
|
||||||
|
|
||||||
class PlayerInactiveError(BaseError):
|
class PlayerInactiveError(BaseError):
|
||||||
...
|
detail = "Player inactive"
|
||||||
|
|
||||||
|
|
||||||
class PlayerNotFoundError(BaseError):
|
class PlayerNotFoundError(BaseError):
|
||||||
...
|
detail = "Player not found"
|
||||||
|
|
||||||
|
|
||||||
|
class GameLockedError(BaseError):
|
||||||
|
detail = "Game locked. Product selection in progress."
|
||||||
|
|
||||||
|
|
||||||
class ValidationError(BaseError):
|
class ValidationError(BaseError):
|
||||||
...
|
detail = "Validation error"
|
||||||
|
|
||||||
|
|
||||||
class Direction(str, Enum):
|
class Direction(str, Enum):
|
||||||
@ -63,12 +70,6 @@ class Player(BaseModel):
|
|||||||
state: PlayerState
|
state: PlayerState
|
||||||
|
|
||||||
|
|
||||||
class Product(BaseModel):
|
|
||||||
name: str
|
|
||||||
id: str
|
|
||||||
description: Optional[str] = None
|
|
||||||
|
|
||||||
|
|
||||||
class PingResponse(BaseModel):
|
class PingResponse(BaseModel):
|
||||||
message: str
|
message: str
|
||||||
|
|
||||||
@ -88,10 +89,6 @@ class GameInfoResponse(BaseModel):
|
|||||||
destination: Destination
|
destination: Destination
|
||||||
|
|
||||||
|
|
||||||
class ProductListResponse(BaseModel):
|
|
||||||
products: List[Product]
|
|
||||||
|
|
||||||
|
|
||||||
class FairHopper:
|
class FairHopper:
|
||||||
def __init__(self, host: str) -> None:
|
def __init__(self, host: str) -> None:
|
||||||
self.host = host
|
self.host = host
|
||||||
@ -160,42 +157,9 @@ class FairHopper:
|
|||||||
raise PositionError()
|
raise PositionError()
|
||||||
elif r.status_code == 422:
|
elif r.status_code == 422:
|
||||||
raise ValidationError()
|
raise ValidationError()
|
||||||
|
elif r.status_code == 423:
|
||||||
|
raise GameLockedError()
|
||||||
else:
|
else:
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
|
||||||
return PlayerInfoResponse(**r.json())
|
return PlayerInfoResponse(**r.json())
|
||||||
|
|
||||||
def get_products(self) -> List[Product]:
|
|
||||||
r = requests.get(self.format_url("/products"))
|
|
||||||
response_data = ProductListResponse(**r.json())
|
|
||||||
return response_data.products
|
|
||||||
|
|
||||||
def get_product(self, product_id: str) -> Product:
|
|
||||||
r = requests.get(self.format_url(f"/products/{product_id}"))
|
|
||||||
|
|
||||||
if r.status_code == 422:
|
|
||||||
raise ValidationError()
|
|
||||||
else:
|
|
||||||
r.raise_for_status()
|
|
||||||
|
|
||||||
return Product(**r.json())
|
|
||||||
|
|
||||||
def purchase_product(self, player_id: str, product_id: str) -> Product:
|
|
||||||
url = self.format_url(f"/player/{player_id}/product/purchase")
|
|
||||||
payload = {
|
|
||||||
"product_id": product_id,
|
|
||||||
}
|
|
||||||
r = requests.post(url, json=payload)
|
|
||||||
|
|
||||||
if r.status_code == 403:
|
|
||||||
raise PlayerInactiveError()
|
|
||||||
elif r.status_code == 404:
|
|
||||||
raise PlayerNotFoundError()
|
|
||||||
elif r.status_code == 409:
|
|
||||||
raise PositionError()
|
|
||||||
elif r.status_code == 422:
|
|
||||||
raise ValidationError()
|
|
||||||
else:
|
|
||||||
r.raise_for_status()
|
|
||||||
|
|
||||||
return Product(**r.json())
|
|
||||||
|
|||||||
2
python/requirements.txt
Normal file
2
python/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pydantic
|
||||||
|
requests
|
||||||
Reference in New Issue
Block a user