starport 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- starport-1.0.0/LICENSE +21 -0
- starport-1.0.0/PKG-INFO +278 -0
- starport-1.0.0/README.md +252 -0
- starport-1.0.0/pyproject.toml +159 -0
- starport-1.0.0/src/starport/__init__.py +40 -0
- starport-1.0.0/src/starport/__version__.py +3 -0
- starport-1.0.0/src/starport/app.py +1054 -0
- starport-1.0.0/src/starport/attrdict.py +83 -0
- starport-1.0.0/src/starport/config.py +131 -0
- starport-1.0.0/src/starport/exceptions/__init__.py +7 -0
- starport-1.0.0/src/starport/exceptions/validation.py +40 -0
- starport-1.0.0/src/starport/lazy.py +154 -0
- starport-1.0.0/src/starport/logging.py +297 -0
- starport-1.0.0/src/starport/openapi/__init__.py +17 -0
- starport-1.0.0/src/starport/openapi/generator.py +170 -0
- starport-1.0.0/src/starport/openapi/swagger.py +76 -0
- starport-1.0.0/src/starport/openapi_schema.py +599 -0
- starport-1.0.0/src/starport/params/__init__.py +7 -0
- starport-1.0.0/src/starport/params/__init__.pyi +12 -0
- starport-1.0.0/src/starport/params/basic.py +300 -0
- starport-1.0.0/src/starport/params/basic.pyi +97 -0
- starport-1.0.0/src/starport/params/custom.py +248 -0
- starport-1.0.0/src/starport/params/custom.pyi +40 -0
- starport-1.0.0/src/starport/params/jsonbody.py +312 -0
- starport-1.0.0/src/starport/params/jsonbody.pyi +29 -0
- starport-1.0.0/src/starport/py.typed +0 -0
- starport-1.0.0/src/starport/requests.py +4 -0
- starport-1.0.0/src/starport/responses.py +384 -0
- starport-1.0.0/src/starport/router.py +2196 -0
- starport-1.0.0/src/starport/status.py +8 -0
- starport-1.0.0/src/starport/validation.py +157 -0
starport-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 alpine
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
starport-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: starport
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Explicit, AI-Ready Web Framework
|
|
5
|
+
Keywords:
|
|
6
|
+
Author: alpine
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Database
|
|
18
|
+
Requires-Dist: starlette>=0.39.0
|
|
19
|
+
Requires-Dist: pyjson5>=2.0.0
|
|
20
|
+
Requires-Dist: python-multipart>=0.0.21
|
|
21
|
+
Requires-Dist: jsonschema>=4 ; extra == 'validate'
|
|
22
|
+
Requires-Dist: openapi-spec-validator>=0.7 ; extra == 'validate'
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Provides-Extra: validate
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# Starport
|
|
28
|
+
|
|
29
|
+
**Explicit, AI-Ready Web Framework**
|
|
30
|
+
|
|
31
|
+
A minimalist abstraction for Starlette, optimized for the AI era.
|
|
32
|
+
|
|
33
|
+
[](https://www.python.org/downloads/)
|
|
34
|
+
|
|
35
|
+

|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 概要
|
|
40
|
+
|
|
41
|
+
**Starport** は実装者の意図を明示的にし、AIがその意図を正確に汲み取れる構造を第一に考えて設計された、Starlette ベースの Web フレームワークです。
|
|
42
|
+
|
|
43
|
+
### 設計思想
|
|
44
|
+
|
|
45
|
+
1. **シンプルさ** - 不要な抽象化を排除、直感的なAPI
|
|
46
|
+
2. **AI Ready** - サンプル駆動のドキュメント、コードとドキュメントの一体化
|
|
47
|
+
3. **適切な抽象化** - 隠蔽ではなく、必要に応じて Starlette を活用
|
|
48
|
+
|
|
49
|
+
### 主な特徴
|
|
50
|
+
|
|
51
|
+
- ✅ **明示的設計 (Explicit)** - 暗黙的な動作を排除、意図が明確なコード
|
|
52
|
+
- ✅ **AI Ready** - JSON5リテラルによるサンプル駆動のドキュメント生成
|
|
53
|
+
- ✅ **軽量** - Pydantic不使用、必要最小限の依存関係
|
|
54
|
+
- ✅ **直感的** - `body.name` のような自然なアクセス、戻り値の型ヒントで動作を制御
|
|
55
|
+
- ✅ **OpenAPI 3.0** - 自動ドキュメント生成と Swagger UI
|
|
56
|
+
- ✅ **Secure by Default** - OpenAPIはデフォルト無効、本番環境での情報露出を防止
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## クイックスタート
|
|
61
|
+
|
|
62
|
+
### 基本的な実装
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from starport import Router
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
app = Router(
|
|
69
|
+
openapi_url="/openapi.json",
|
|
70
|
+
docs_url="/docs",
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
@app.get("/helloworld")
|
|
74
|
+
def helloworld() -> str:
|
|
75
|
+
return "Hello, World!"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@app.get("/users")
|
|
79
|
+
def get_users() -> list:
|
|
80
|
+
return [{"id": "user_001", "name": "海野 彼方"}]
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
if __name__ == "__main__":
|
|
84
|
+
import uvicorn
|
|
85
|
+
print("Swagger UI is available at http://127.0.0.1:8000/docs")
|
|
86
|
+
uvicorn.run(app, host="127.0.0.1", port=8000)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### AI Ready のサンプル
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from starport import Router
|
|
93
|
+
from starport.params import JsonBody, Query
|
|
94
|
+
|
|
95
|
+
app = Router(
|
|
96
|
+
openapi_url="/openapi.json",
|
|
97
|
+
docs_url="/docs",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@app.get(
|
|
102
|
+
"/users",
|
|
103
|
+
spec="""[{
|
|
104
|
+
id: "user001", // ユーザーID
|
|
105
|
+
name: "山田太郎", // 表示名
|
|
106
|
+
email: "yamada@example.com", // メールアドレス
|
|
107
|
+
"role?": "admin", // ロール(オプショナル)
|
|
108
|
+
created_at: "2024-01-01T00:00:00Z" // 作成日時
|
|
109
|
+
}]"""
|
|
110
|
+
)
|
|
111
|
+
def list_users(
|
|
112
|
+
page: int = Query(1, ge=1, description="ページ番号"),
|
|
113
|
+
limit: int = Query(100, ge=1, le=1000, description="取得件数"),
|
|
114
|
+
role: str = Query(None, description="ロールでフィルタ")
|
|
115
|
+
) -> list[dict]:
|
|
116
|
+
"""
|
|
117
|
+
ユーザー一覧を取得(最も基本的なパターン)
|
|
118
|
+
|
|
119
|
+
spec: レスポンスの構造を文書化(配列形式)
|
|
120
|
+
Query: パラメータを個別に定義(バリデーション付き)
|
|
121
|
+
|
|
122
|
+
これが最も実用的で、RESTful な API の基本形です。
|
|
123
|
+
"""
|
|
124
|
+
# 簡易的な実装
|
|
125
|
+
users = [
|
|
126
|
+
{
|
|
127
|
+
"id": "user001",
|
|
128
|
+
"name": "山田太郎",
|
|
129
|
+
"email": "yamada@example.com",
|
|
130
|
+
"role": "admin",
|
|
131
|
+
"created_at": "2024-01-01T00:00:00Z"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"id": "user002",
|
|
135
|
+
"name": "佐藤花子",
|
|
136
|
+
"email": "sato@example.com",
|
|
137
|
+
"created_at": "2024-01-02T00:00:00Z"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"id": "user003",
|
|
141
|
+
"name": "鈴木一郎",
|
|
142
|
+
"email": "suzuki@example.com",
|
|
143
|
+
"role": "user",
|
|
144
|
+
"created_at": "2024-01-03T00:00:00Z"
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
# ロールでフィルタ
|
|
149
|
+
if role:
|
|
150
|
+
users = [u for u in users if u.get("role") == role]
|
|
151
|
+
|
|
152
|
+
# ページネーション
|
|
153
|
+
start = (page - 1) * limit
|
|
154
|
+
end = start + limit
|
|
155
|
+
|
|
156
|
+
return users[start:end]
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
if __name__ == "__main__":
|
|
160
|
+
import uvicorn
|
|
161
|
+
print("Swagger UI is available at http://127.0.0.1:8000/docs")
|
|
162
|
+
uvicorn.run(app, host="127.0.0.1", port=8000)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### uv を使った実行方法
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# プロジェクト作成
|
|
169
|
+
uv init hello-starport
|
|
170
|
+
cd hello-starport/
|
|
171
|
+
|
|
172
|
+
# Starport と Uvicorn のインストール
|
|
173
|
+
uv add git+https://github.com/kinto-dev/starport.git
|
|
174
|
+
uv add uvicorn
|
|
175
|
+
|
|
176
|
+
# コードを作成
|
|
177
|
+
cat > main.py
|
|
178
|
+
# (上記のサンプルコードをペーストして Ctrl+D)
|
|
179
|
+
|
|
180
|
+
# サーバー起動
|
|
181
|
+
uv run main.py
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Swagger UI: http://127.0.0.1:8000/docs
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## スケールするための設計 (Scalable by Design)
|
|
190
|
+
|
|
191
|
+
Starport は、小規模なスクリプトから大規模なアプリケーションまで対応可能です。
|
|
192
|
+
App を使って、機能を独立したモジュールとして分割・統合できます。
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
from starport import App, Route
|
|
197
|
+
|
|
198
|
+
app = App(
|
|
199
|
+
routes=[
|
|
200
|
+
Route("/todos", "myapp.todos:router"),
|
|
201
|
+
Route("/auth", "myapp.auth:router"),
|
|
202
|
+
],
|
|
203
|
+
lazy=True,
|
|
204
|
+
title="My API",
|
|
205
|
+
version="1.0.0",
|
|
206
|
+
openapi_url="/openapi.json",
|
|
207
|
+
docs_url="/docs",
|
|
208
|
+
)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### 疎結合なマルチ・ルーター構成
|
|
212
|
+
|
|
213
|
+
FastAPI 等で見られる「インポート時に親 App へ登録する」方式ではなく、
|
|
214
|
+
各ルーターを完全に独立した ASGI アプリとして定義し、後から統合する設計を採用しています。
|
|
215
|
+
これにより、循環参照を防止し、各機能を単体でテスト・実行することが容易になります。
|
|
216
|
+
|
|
217
|
+
### lazy mount
|
|
218
|
+
App は初回リクエスト時にルーターをロード(import)することで、
|
|
219
|
+
大規模アプリケーション(100+ routes)での開発体験を改善します。
|
|
220
|
+
|
|
221
|
+
- サーバレス環境(AWS Lambda等)の cold start 最適化
|
|
222
|
+
- 開発時の Hot-swap の高速化
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## ドキュメント
|
|
228
|
+
|
|
229
|
+
### 学習ガイド
|
|
230
|
+
- **[クイックスタート](docs/user/quickstart.md)** - 30分で始める Starport
|
|
231
|
+
- **[開発者ガイド](docs/user/guide.md)** - AI Ready な API 設計と大規模開発
|
|
232
|
+
- **[Spring Boot ユーザー向け入門](docs/user/introduction-for-spring-boot-users.md)** - Spring Boot からの移行ガイド
|
|
233
|
+
|
|
234
|
+
### リファレンス
|
|
235
|
+
- **[OpenAPI スキーマガイド](docs/user/openapi-schema-guide.md)** - JSON5によるスキーマ定義
|
|
236
|
+
|
|
237
|
+
### 実装例
|
|
238
|
+
- **[Examples](examples/)** - 実装サンプル集
|
|
239
|
+
|
|
240
|
+
### 設計資料
|
|
241
|
+
- **[設計原則](docs/dev/design-principles.md)** - Starport の設計思想
|
|
242
|
+
- **[ADR](docs/dev/adr/)** - アーキテクチャ決定記録
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## 開発
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
# 環境構築
|
|
250
|
+
uv sync
|
|
251
|
+
|
|
252
|
+
# テスト実行
|
|
253
|
+
uv run pytest
|
|
254
|
+
|
|
255
|
+
# サンプル実行
|
|
256
|
+
uv run python -m examples.basics.basic
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## インストール
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
# uv を使用する場合
|
|
265
|
+
uv add git+https://github.com/kinto-dev/starport.git
|
|
266
|
+
|
|
267
|
+
# pip を使用する場合
|
|
268
|
+
pip install git+https://github.com/kinto-dev/starport.git
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**注意**: Starport は現在開発中のため、PyPI での公開は未定です。
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 関連プロジェクト
|
|
276
|
+
|
|
277
|
+
- **[Starlette](https://www.starlette.io/)** - Starport の基盤となる ASGI フレームワーク
|
|
278
|
+
- **[FastAPI](https://fastapi.tiangolo.com/)** - Starport のインスピレーション元
|
starport-1.0.0/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Starport
|
|
2
|
+
|
|
3
|
+
**Explicit, AI-Ready Web Framework**
|
|
4
|
+
|
|
5
|
+
A minimalist abstraction for Starlette, optimized for the AI era.
|
|
6
|
+
|
|
7
|
+
[](https://www.python.org/downloads/)
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 概要
|
|
14
|
+
|
|
15
|
+
**Starport** は実装者の意図を明示的にし、AIがその意図を正確に汲み取れる構造を第一に考えて設計された、Starlette ベースの Web フレームワークです。
|
|
16
|
+
|
|
17
|
+
### 設計思想
|
|
18
|
+
|
|
19
|
+
1. **シンプルさ** - 不要な抽象化を排除、直感的なAPI
|
|
20
|
+
2. **AI Ready** - サンプル駆動のドキュメント、コードとドキュメントの一体化
|
|
21
|
+
3. **適切な抽象化** - 隠蔽ではなく、必要に応じて Starlette を活用
|
|
22
|
+
|
|
23
|
+
### 主な特徴
|
|
24
|
+
|
|
25
|
+
- ✅ **明示的設計 (Explicit)** - 暗黙的な動作を排除、意図が明確なコード
|
|
26
|
+
- ✅ **AI Ready** - JSON5リテラルによるサンプル駆動のドキュメント生成
|
|
27
|
+
- ✅ **軽量** - Pydantic不使用、必要最小限の依存関係
|
|
28
|
+
- ✅ **直感的** - `body.name` のような自然なアクセス、戻り値の型ヒントで動作を制御
|
|
29
|
+
- ✅ **OpenAPI 3.0** - 自動ドキュメント生成と Swagger UI
|
|
30
|
+
- ✅ **Secure by Default** - OpenAPIはデフォルト無効、本番環境での情報露出を防止
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## クイックスタート
|
|
35
|
+
|
|
36
|
+
### 基本的な実装
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from starport import Router
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
app = Router(
|
|
43
|
+
openapi_url="/openapi.json",
|
|
44
|
+
docs_url="/docs",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
@app.get("/helloworld")
|
|
48
|
+
def helloworld() -> str:
|
|
49
|
+
return "Hello, World!"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@app.get("/users")
|
|
53
|
+
def get_users() -> list:
|
|
54
|
+
return [{"id": "user_001", "name": "海野 彼方"}]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
if __name__ == "__main__":
|
|
58
|
+
import uvicorn
|
|
59
|
+
print("Swagger UI is available at http://127.0.0.1:8000/docs")
|
|
60
|
+
uvicorn.run(app, host="127.0.0.1", port=8000)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### AI Ready のサンプル
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from starport import Router
|
|
67
|
+
from starport.params import JsonBody, Query
|
|
68
|
+
|
|
69
|
+
app = Router(
|
|
70
|
+
openapi_url="/openapi.json",
|
|
71
|
+
docs_url="/docs",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@app.get(
|
|
76
|
+
"/users",
|
|
77
|
+
spec="""[{
|
|
78
|
+
id: "user001", // ユーザーID
|
|
79
|
+
name: "山田太郎", // 表示名
|
|
80
|
+
email: "yamada@example.com", // メールアドレス
|
|
81
|
+
"role?": "admin", // ロール(オプショナル)
|
|
82
|
+
created_at: "2024-01-01T00:00:00Z" // 作成日時
|
|
83
|
+
}]"""
|
|
84
|
+
)
|
|
85
|
+
def list_users(
|
|
86
|
+
page: int = Query(1, ge=1, description="ページ番号"),
|
|
87
|
+
limit: int = Query(100, ge=1, le=1000, description="取得件数"),
|
|
88
|
+
role: str = Query(None, description="ロールでフィルタ")
|
|
89
|
+
) -> list[dict]:
|
|
90
|
+
"""
|
|
91
|
+
ユーザー一覧を取得(最も基本的なパターン)
|
|
92
|
+
|
|
93
|
+
spec: レスポンスの構造を文書化(配列形式)
|
|
94
|
+
Query: パラメータを個別に定義(バリデーション付き)
|
|
95
|
+
|
|
96
|
+
これが最も実用的で、RESTful な API の基本形です。
|
|
97
|
+
"""
|
|
98
|
+
# 簡易的な実装
|
|
99
|
+
users = [
|
|
100
|
+
{
|
|
101
|
+
"id": "user001",
|
|
102
|
+
"name": "山田太郎",
|
|
103
|
+
"email": "yamada@example.com",
|
|
104
|
+
"role": "admin",
|
|
105
|
+
"created_at": "2024-01-01T00:00:00Z"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"id": "user002",
|
|
109
|
+
"name": "佐藤花子",
|
|
110
|
+
"email": "sato@example.com",
|
|
111
|
+
"created_at": "2024-01-02T00:00:00Z"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"id": "user003",
|
|
115
|
+
"name": "鈴木一郎",
|
|
116
|
+
"email": "suzuki@example.com",
|
|
117
|
+
"role": "user",
|
|
118
|
+
"created_at": "2024-01-03T00:00:00Z"
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
# ロールでフィルタ
|
|
123
|
+
if role:
|
|
124
|
+
users = [u for u in users if u.get("role") == role]
|
|
125
|
+
|
|
126
|
+
# ページネーション
|
|
127
|
+
start = (page - 1) * limit
|
|
128
|
+
end = start + limit
|
|
129
|
+
|
|
130
|
+
return users[start:end]
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
if __name__ == "__main__":
|
|
134
|
+
import uvicorn
|
|
135
|
+
print("Swagger UI is available at http://127.0.0.1:8000/docs")
|
|
136
|
+
uvicorn.run(app, host="127.0.0.1", port=8000)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### uv を使った実行方法
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# プロジェクト作成
|
|
143
|
+
uv init hello-starport
|
|
144
|
+
cd hello-starport/
|
|
145
|
+
|
|
146
|
+
# Starport と Uvicorn のインストール
|
|
147
|
+
uv add git+https://github.com/kinto-dev/starport.git
|
|
148
|
+
uv add uvicorn
|
|
149
|
+
|
|
150
|
+
# コードを作成
|
|
151
|
+
cat > main.py
|
|
152
|
+
# (上記のサンプルコードをペーストして Ctrl+D)
|
|
153
|
+
|
|
154
|
+
# サーバー起動
|
|
155
|
+
uv run main.py
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Swagger UI: http://127.0.0.1:8000/docs
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## スケールするための設計 (Scalable by Design)
|
|
164
|
+
|
|
165
|
+
Starport は、小規模なスクリプトから大規模なアプリケーションまで対応可能です。
|
|
166
|
+
App を使って、機能を独立したモジュールとして分割・統合できます。
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from starport import App, Route
|
|
171
|
+
|
|
172
|
+
app = App(
|
|
173
|
+
routes=[
|
|
174
|
+
Route("/todos", "myapp.todos:router"),
|
|
175
|
+
Route("/auth", "myapp.auth:router"),
|
|
176
|
+
],
|
|
177
|
+
lazy=True,
|
|
178
|
+
title="My API",
|
|
179
|
+
version="1.0.0",
|
|
180
|
+
openapi_url="/openapi.json",
|
|
181
|
+
docs_url="/docs",
|
|
182
|
+
)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 疎結合なマルチ・ルーター構成
|
|
186
|
+
|
|
187
|
+
FastAPI 等で見られる「インポート時に親 App へ登録する」方式ではなく、
|
|
188
|
+
各ルーターを完全に独立した ASGI アプリとして定義し、後から統合する設計を採用しています。
|
|
189
|
+
これにより、循環参照を防止し、各機能を単体でテスト・実行することが容易になります。
|
|
190
|
+
|
|
191
|
+
### lazy mount
|
|
192
|
+
App は初回リクエスト時にルーターをロード(import)することで、
|
|
193
|
+
大規模アプリケーション(100+ routes)での開発体験を改善します。
|
|
194
|
+
|
|
195
|
+
- サーバレス環境(AWS Lambda等)の cold start 最適化
|
|
196
|
+
- 開発時の Hot-swap の高速化
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## ドキュメント
|
|
202
|
+
|
|
203
|
+
### 学習ガイド
|
|
204
|
+
- **[クイックスタート](docs/user/quickstart.md)** - 30分で始める Starport
|
|
205
|
+
- **[開発者ガイド](docs/user/guide.md)** - AI Ready な API 設計と大規模開発
|
|
206
|
+
- **[Spring Boot ユーザー向け入門](docs/user/introduction-for-spring-boot-users.md)** - Spring Boot からの移行ガイド
|
|
207
|
+
|
|
208
|
+
### リファレンス
|
|
209
|
+
- **[OpenAPI スキーマガイド](docs/user/openapi-schema-guide.md)** - JSON5によるスキーマ定義
|
|
210
|
+
|
|
211
|
+
### 実装例
|
|
212
|
+
- **[Examples](examples/)** - 実装サンプル集
|
|
213
|
+
|
|
214
|
+
### 設計資料
|
|
215
|
+
- **[設計原則](docs/dev/design-principles.md)** - Starport の設計思想
|
|
216
|
+
- **[ADR](docs/dev/adr/)** - アーキテクチャ決定記録
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 開発
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# 環境構築
|
|
224
|
+
uv sync
|
|
225
|
+
|
|
226
|
+
# テスト実行
|
|
227
|
+
uv run pytest
|
|
228
|
+
|
|
229
|
+
# サンプル実行
|
|
230
|
+
uv run python -m examples.basics.basic
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## インストール
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# uv を使用する場合
|
|
239
|
+
uv add git+https://github.com/kinto-dev/starport.git
|
|
240
|
+
|
|
241
|
+
# pip を使用する場合
|
|
242
|
+
pip install git+https://github.com/kinto-dev/starport.git
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**注意**: Starport は現在開発中のため、PyPI での公開は未定です。
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 関連プロジェクト
|
|
250
|
+
|
|
251
|
+
- **[Starlette](https://www.starlette.io/)** - Starport の基盤となる ASGI フレームワーク
|
|
252
|
+
- **[FastAPI](https://fastapi.tiangolo.com/)** - Starport のインスピレーション元
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build>=0.11.15,<0.12"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "starport"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Explicit, AI-Ready Web Framework"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "alpine" },
|
|
14
|
+
]
|
|
15
|
+
keywords = []
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Topic :: Database",
|
|
26
|
+
]
|
|
27
|
+
requires-python = ">=3.10"
|
|
28
|
+
dependencies = [
|
|
29
|
+
"starlette>=0.39.0",
|
|
30
|
+
"pyjson5>=2.0.0",
|
|
31
|
+
"python-multipart>=0.0.21",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.optional-dependencies]
|
|
35
|
+
validate = [
|
|
36
|
+
# STARPORT_VALIDATE_SPEC=1
|
|
37
|
+
"jsonschema>=4",
|
|
38
|
+
# STARPORT_VALIDATE_OPENAPI=1
|
|
39
|
+
"openapi-spec-validator>=0.7",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[project.scripts]
|
|
43
|
+
#starport = "starport.cli.main:main"
|
|
44
|
+
|
|
45
|
+
[dependency-groups]
|
|
46
|
+
dev = [
|
|
47
|
+
# validate
|
|
48
|
+
"jsonschema",
|
|
49
|
+
"openapi-spec-validator",
|
|
50
|
+
# Web server
|
|
51
|
+
"uvicorn[standard]>=0.38.0",
|
|
52
|
+
# Linting
|
|
53
|
+
"ruff",
|
|
54
|
+
#-- pytest --
|
|
55
|
+
"pytest>=7.0.0",
|
|
56
|
+
"pytest-cov>=4.0.0",
|
|
57
|
+
"pytest-mock>=3.10.0",
|
|
58
|
+
"pytest-benchmark>=5.2.3",
|
|
59
|
+
"httpx>=0.28.1",
|
|
60
|
+
"fastapi>=0.141.1",
|
|
61
|
+
#-- dev-docs skill --
|
|
62
|
+
"pyyaml>=6.0.3",
|
|
63
|
+
"pytest-env>=1.6.0",
|
|
64
|
+
"pytest-asyncio>=1.4.0",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
[tool.uv]
|
|
69
|
+
package = true
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
[tool.ruff]
|
|
73
|
+
# https://docs.astral.sh/ruff/configuration/
|
|
74
|
+
include = ["src/**/*.py", "tests/**/*.py", "scripts/**/*.py"]
|
|
75
|
+
cache-dir = "var/.ruff_cache"
|
|
76
|
+
target-version = "py310"
|
|
77
|
+
preview = true
|
|
78
|
+
# unsafe-fixes = true
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
[tool.ruff.lint]
|
|
82
|
+
# https://docs.astral.sh/ruff/rules/
|
|
83
|
+
select = [
|
|
84
|
+
# pycodestyle (E, W)
|
|
85
|
+
"E2",
|
|
86
|
+
"E4",
|
|
87
|
+
"E7",
|
|
88
|
+
"E9",
|
|
89
|
+
"W",
|
|
90
|
+
|
|
91
|
+
# Pyflakes (F)
|
|
92
|
+
"F",
|
|
93
|
+
|
|
94
|
+
# flake8-no-pep420 (INP)
|
|
95
|
+
"INP",
|
|
96
|
+
|
|
97
|
+
# pep8-naming (N)
|
|
98
|
+
#"N",
|
|
99
|
+
]
|
|
100
|
+
ignore = [
|
|
101
|
+
"W293", # Blank line contains whitespace
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
[tool.ruff.lint.per-file-ignores]
|
|
105
|
+
"docker/*.py" = ["INP"]
|
|
106
|
+
"scripts/*.py" = ["INP"]
|
|
107
|
+
"tests/*.py" = ["INP"]
|
|
108
|
+
"var/*.py" = ["INP"]
|
|
109
|
+
|
|
110
|
+
[tool.ruff.lint.pycodestyle]
|
|
111
|
+
max-line-length = 130
|
|
112
|
+
|
|
113
|
+
[tool.pytest.ini_options]
|
|
114
|
+
testpaths = ["tests", "examples"]
|
|
115
|
+
pythonpath = ["src"]
|
|
116
|
+
asyncio_mode = "auto"
|
|
117
|
+
cache_dir = "var/.pytest_cache"
|
|
118
|
+
|
|
119
|
+
log_level = "INFO"
|
|
120
|
+
log_cli = true
|
|
121
|
+
log_cli_level = "INFO"
|
|
122
|
+
log_cli_format = "%(asctime)s.%(msecs)03d [%(levelname)s] %(name)s:%(lineno)d - %(message)s"
|
|
123
|
+
log_file = "var/log/pytest.log"
|
|
124
|
+
log_file_level = "INFO"
|
|
125
|
+
log_file_format = "%(asctime)s [%(levelname)s] <%(threadName)s> %(name)s:%(lineno)d - %(message)s"
|
|
126
|
+
|
|
127
|
+
# pytest-benchmark
|
|
128
|
+
# - https://pytest-benchmark.readthedocs.io/en/latest/usage.html
|
|
129
|
+
#
|
|
130
|
+
# use --benchmark-only to run them. This overrides –-benchmark-skip.
|
|
131
|
+
# ❯ pytest --benchmark-only [-k <test_name>]
|
|
132
|
+
addopts = "--benchmark-skip"
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
[tool.pytest_env]
|
|
136
|
+
STARPORT_VALIDATE_OPENAPI = 1
|
|
137
|
+
STARPORT_VALIDATE_SPEC = 1
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
[tool.coverage.run]
|
|
141
|
+
source = ["src"]
|
|
142
|
+
data_file = "var/.coverage"
|
|
143
|
+
omit = [
|
|
144
|
+
"tests/*",
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
[tool.coverage.report]
|
|
148
|
+
exclude_lines = [
|
|
149
|
+
"pragma: no cover",
|
|
150
|
+
"def __repr__",
|
|
151
|
+
"if self.debug:",
|
|
152
|
+
"if settings.DEBUG",
|
|
153
|
+
"raise AssertionError",
|
|
154
|
+
"raise NotImplementedError",
|
|
155
|
+
"if 0:",
|
|
156
|
+
"if __name__ == .__main__.:",
|
|
157
|
+
"class .*\\bProtocol\\):",
|
|
158
|
+
"@(abc\\.)?abstractmethod",
|
|
159
|
+
]
|