README
¶
JSON API Example
This example demonstrates how to build a REST API with HyperServe that handles JSON requests and responses. It implements a simple TODO list API with full CRUD operations.
What This Example Shows
- Building REST endpoints with proper HTTP methods
- Parsing JSON request bodies
- Sending JSON responses
- Error handling with appropriate status codes
- Thread-safe in-memory data storage
- CORS configuration for browser access
- RESTful URL patterns
API Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | / |
API information |
| GET | /todos |
List all todos |
| POST | /todos |
Create a new todo |
| GET | /todos/{id} |
Get a specific todo |
| PUT | /todos/{id} |
Update a todo |
| DELETE | /todos/{id} |
Delete a todo |
Running the Example
go run ./examples/json-api
The API server will start on http://localhost:8080
Testing the API
Using curl
# Get API info
curl http://localhost:8080/
# List all todos
curl http://localhost:8080/todos
# Create a new todo
curl -X POST http://localhost:8080/todos \
-H "Content-Type: application/json" \
-d '{"title":"Buy groceries"}'
# Get a specific todo
curl http://localhost:8080/todos/1
# Update a todo
curl -X PUT http://localhost:8080/todos/1 \
-H "Content-Type: application/json" \
-d '{"title":"Buy groceries","completed":true}'
# Delete a todo
curl -X DELETE http://localhost:8080/todos/1
Using a REST client
You can also use tools like:
From JavaScript
// Create a todo
fetch('http://localhost:8080/todos', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({title: 'Learn HyperServe'})
})
.then(res => res.json())
.then(todo => console.log('Created:', todo));
// List todos
fetch('http://localhost:8080/todos')
.then(res => res.json())
.then(todos => console.log('Todos:', todos));
Key Concepts
1. JSON Response Helper
func sendJSON(w http.ResponseWriter, status int, data any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(data)
}
This helper ensures consistent JSON responses with proper headers.
2. Error Handling
func sendError(w http.ResponseWriter, status int, message string) {
sendJSON(w, status, map[string]string{"error": message})
}
Errors are returned as JSON with appropriate HTTP status codes.
3. Request Body Parsing
var input struct {
Title string `json:"title"`
}
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
sendError(w, http.StatusBadRequest, "Invalid JSON")
return
}
Using json.Decoder for efficient streaming JSON parsing.
4. Thread-Safe Storage
type TodoStore struct {
mu sync.RWMutex // Allows multiple readers
todos map[int]*Todo
nextID int
}
The store uses sync.RWMutex for concurrent access safety.
5. Method-Aware Routing
srv.GET("/todos/{id}", getTodo)
srv.PUT("/todos/{id}", updateTodo)
srv.DELETE("/todos/{id}", deleteTodo)
Common Patterns
Input Validation
if input.Title == "" {
sendError(w, http.StatusBadRequest, "Title is required")
return
}
404 Handling
todo, exists := store.Get(id)
if !exists {
sendError(w, http.StatusNotFound, "Todo not found")
return
}
Status Codes
- 200 OK - Successful GET/PUT
- 201 Created - Successful POST
- 400 Bad Request - Invalid input
- 404 Not Found - Resource doesn't exist
- 405 Method Not Allowed - Wrong HTTP method
Try These Modifications
- Add Pagination: Implement
?page=1&limit=10for the list endpoint - Add Filtering: Allow
?completed=trueto filter todos - Add Validation: More robust input validation
- Add Timestamps: Track
updated_attime - Add Search: Implement
?q=groceryto search titles
Production Considerations
This example uses in-memory storage for simplicity. In production, you would:
- Use a real database (PostgreSQL, MySQL, MongoDB, etc.)
- Add authentication middleware
- Implement rate limiting
- Add request logging
- Use environment variables for configuration
- Add input sanitization
- Implement proper error logging
What's Next?
Now that you can build APIs, move on to middleware-basics to learn about HyperServe's middleware system.
Documentation
¶
There is no documentation for this package.
Click to show internal directories.
Click to hide internal directories.