405 lines
No EOL
7.9 KiB
Markdown
405 lines
No EOL
7.9 KiB
Markdown
# API Documentation — go-first / URPI
|
|
|
|
Base URL: `https://www.urpi.be/api/v1`
|
|
Local: `http://localhost:8080/api/v1`
|
|
|
|
All responses follow a consistent envelope format.
|
|
|
|
---
|
|
|
|
## Response Format
|
|
|
|
### Success
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {},
|
|
"meta": {
|
|
"page": 1,
|
|
"page_size": 20,
|
|
"total": 100,
|
|
"total_pages": 5
|
|
}
|
|
}
|
|
```
|
|
|
|
### Error
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "ERROR_CODE",
|
|
"message": "Human readable message",
|
|
"details": "Optional technical details"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Common Error Codes
|
|
|
|
| Code | HTTP Status | Description |
|
|
|------|-------------|-------------|
|
|
| `VALIDATION_ERROR` | 400 | Request body validation failed |
|
|
| `INVALID_ID` | 400 | UUID format invalid |
|
|
| `NOT_FOUND` | 404 | Resource not found |
|
|
| `UNAUTHORIZED` | 401 | Authentication required |
|
|
| `FORBIDDEN` | 403 | Insufficient permissions |
|
|
| `CONFLICT` | 409 | Resource conflict |
|
|
| `RATE_LIMITED` | 429 | Too many requests |
|
|
| `INTERNAL_ERROR` | 500 | Server error |
|
|
| `SERVICE_UNAVAILABLE` | 503 | Service temporarily unavailable |
|
|
|
|
---
|
|
|
|
## Endpoints
|
|
|
|
### Health Check
|
|
|
|
**GET** `/health`
|
|
|
|
No authentication required.
|
|
|
|
#### Response
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"status": "ok",
|
|
"service": "go-first",
|
|
"version": "1.0.0"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Skills
|
|
|
|
#### List Skills
|
|
|
|
**GET** `/skills`
|
|
|
|
| Query Param | Type | Description |
|
|
|-------------|------|-------------|
|
|
| `category` | string | Filter by category (Backend, Frontend, Architecture, DevOps, Database, API) |
|
|
|
|
#### Response
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"id": "uuid",
|
|
"name": "Go",
|
|
"category": "Backend",
|
|
"proficiency": 5,
|
|
"icon": "go",
|
|
"order": 1,
|
|
"created_at": "2024-01-01T00:00:00Z",
|
|
"updated_at": "2024-01-01T00:00:00Z"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
#### Get Skill
|
|
|
|
**GET** `/skills/:id`
|
|
|
|
| Path Param | Type | Description |
|
|
|------------|------|-------------|
|
|
| `id` | uuid | Skill UUID |
|
|
|
|
#### Response
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": "uuid",
|
|
"name": "Go",
|
|
"category": "Backend",
|
|
"proficiency": 5,
|
|
"icon": "go",
|
|
"order": 1,
|
|
"created_at": "2024-01-01T00:00:00Z",
|
|
"updated_at": "2024-01-01T00:00:00Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Projects
|
|
|
|
#### List Projects
|
|
|
|
**GET** `/projects`
|
|
|
|
| Query Param | Type | Description |
|
|
|-------------|------|-------------|
|
|
| `category` | string | Filter by category |
|
|
| `featured` | boolean | Filter featured projects only |
|
|
|
|
#### Response
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"id": "uuid",
|
|
"title": "E-Commerce Platform",
|
|
"description": "Full description...",
|
|
"short_desc": "Scalable e-commerce platform...",
|
|
"tech_stack": ["Go", "React", "PostgreSQL", "Redis", "Kubernetes"],
|
|
"image_url": "/images/projects/ecommerce.jpg",
|
|
"demo_url": "https://demo.urpi.be/ecommerce",
|
|
"repo_url": "https://github.com/urpi/ecommerce-platform",
|
|
"category": "Full Stack",
|
|
"featured": true,
|
|
"order": 1,
|
|
"created_at": "2024-01-01T00:00:00Z",
|
|
"updated_at": "2024-01-01T00:00:00Z"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
#### Get Featured Projects
|
|
|
|
**GET** `/projects/featured`
|
|
|
|
Returns only projects with `featured: true`.
|
|
|
|
#### Get Project
|
|
|
|
**GET** `/projects/:id`
|
|
|
|
| Path Param | Type | Description |
|
|
|------------|------|-------------|
|
|
| `id` | uuid | Project UUID |
|
|
|
|
---
|
|
|
|
### Experience
|
|
|
|
#### List Experience
|
|
|
|
**GET** `/experience`
|
|
|
|
Returns all work experience entries ordered by `order` field.
|
|
|
|
#### Response
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"id": "uuid",
|
|
"company": "URPI",
|
|
"role": "Founder & Lead Developer",
|
|
"location": "Belgium",
|
|
"start_date": "2020-01-01T00:00:00Z",
|
|
"end_date": null,
|
|
"current": true,
|
|
"description": "Founded URPI to provide web application...",
|
|
"tech_stack": ["Go", "Java", "React", "Kubernetes", "AWS"],
|
|
"order": 1,
|
|
"created_at": "2024-01-01T00:00:00Z",
|
|
"updated_at": "2024-01-01T00:00:00Z"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Services
|
|
|
|
#### List Services
|
|
|
|
**GET** `/services`
|
|
|
|
Returns all active services offered.
|
|
|
|
#### Response
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"id": "uuid",
|
|
"title": "Web Application Development",
|
|
"description": "Custom web applications built with modern technologies...",
|
|
"icon": "code",
|
|
"features": [
|
|
"React/Next.js Frontend",
|
|
"Go/Java Backend",
|
|
"REST/GraphQL APIs"
|
|
],
|
|
"order": 1,
|
|
"active": true,
|
|
"created_at": "2024-01-01T00:00:00Z",
|
|
"updated_at": "2024-01-01T00:00:00Z"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Contact
|
|
|
|
#### Submit Contact Form
|
|
|
|
**POST** `/contact`
|
|
|
|
Content-Type: `application/json`
|
|
|
|
| Field | Type | Required | Validation |
|
|
|-------|------|----------|------------|
|
|
| `name` | string | Yes | 2-100 chars |
|
|
| `email` | string | Yes | Valid email format |
|
|
| `subject` | string | Yes | 5-200 chars |
|
|
| `message` | string | Yes | 10-5000 chars |
|
|
|
|
#### Request
|
|
```json
|
|
{
|
|
"name": "John Doe",
|
|
"email": "john@example.com",
|
|
"subject": "Project Inquiry",
|
|
"message": "Hello, I'd like to discuss a potential project..."
|
|
}
|
|
```
|
|
|
|
#### Response (201 Created)
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": "uuid",
|
|
"name": "John Doe",
|
|
"email": "john@example.com",
|
|
"subject": "Project Inquiry",
|
|
"message": "Hello, I'd like to discuss a potential project...",
|
|
"status": "new",
|
|
"created_at": "2024-01-15T10:30:00Z",
|
|
"updated_at": "2024-01-15T10:30:00Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Validation Error (400)
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "VALIDATION_ERROR",
|
|
"message": "Invalid request body",
|
|
"details": "Key: 'ContactForm.Email' Error:Field validation for 'Email' failed on the 'email' tag"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Rate Limiting
|
|
|
|
| Endpoint | Limit |
|
|
|----------|-------|
|
|
| `/api/v1/*` (general) | 10 req/s per IP |
|
|
| `/api/v1/contact` | 5 req/min per IP |
|
|
| `/api/v1/health` | No limit |
|
|
|
|
Headers returned:
|
|
- `X-RateLimit-Limit`
|
|
- `X-RateLimit-Remaining`
|
|
- `X-RateLimit-Reset`
|
|
|
|
---
|
|
|
|
## CORS
|
|
|
|
Allowed origins (configured in `config.yaml`):
|
|
- `https://www.urpi.be`
|
|
- `https://urpi.be`
|
|
- `http://localhost:3000`
|
|
- `http://localhost:5173`
|
|
|
|
Allowed methods: `GET, POST, PUT, PATCH, DELETE, OPTIONS`
|
|
Allowed headers: `Origin, Content-Type, Accept, Authorization, X-Requested-With`
|
|
Credentials: `true`
|
|
|
|
---
|
|
|
|
## Versioning
|
|
|
|
API version in URL path: `/api/v1/`
|
|
|
|
Breaking changes will result in `/api/v2/` etc.
|
|
Non-breaking additions (new fields, new endpoints) may be added to v1.
|
|
|
|
---
|
|
|
|
## Authentication
|
|
|
|
Currently **no authentication required** for public endpoints.
|
|
|
|
Future plans:
|
|
- JWT-based auth for admin endpoints
|
|
- API keys for programmatic access
|
|
- OAuth2 for third-party integrations
|
|
|
|
---
|
|
|
|
## SDKs / Clients
|
|
|
|
### JavaScript/TypeScript
|
|
```typescript
|
|
const API_BASE = '/api/v1';
|
|
|
|
async function fetchAPI<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
|
|
const res = await fetch(`${API_BASE}${endpoint}`, {
|
|
headers: { 'Content-Type': 'application/json', ...options.headers },
|
|
...options,
|
|
});
|
|
const data = await res.json();
|
|
if (!res.ok || !data.success) throw new Error(data.error?.message || 'Error');
|
|
return data.data;
|
|
}
|
|
|
|
// Usage
|
|
const skills = await fetchAPI<Skill[]>('/skills');
|
|
const project = await fetchAPI<Project>('/projects/uuid');
|
|
await fetchAPI<ContactSubmission>('/contact', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ name, email, subject, message })
|
|
});
|
|
```
|
|
|
|
### Go
|
|
```go
|
|
type APIResponse struct {
|
|
Success bool `json:"success"`
|
|
Data interface{} `json:"data,omitempty"`
|
|
Error *APIError `json:"error,omitempty"`
|
|
}
|
|
|
|
func GetSkills(ctx context.Context) ([]Skill, error) {
|
|
req, _ := http.NewRequestWithContext(ctx, "GET", "https://www.urpi.be/api/v1/skills", nil)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
// ... parse response
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Changelog
|
|
|
|
### v1.0.0 (2024-01-15)
|
|
- Initial API release
|
|
- Skills, Projects, Experience, Services, Contact endpoints
|
|
- Rate limiting and CORS configuration
|
|
- Health check endpoint |