File: rest-registry.md

package info (click to toggle)
glaze 7.0.2-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 9,036 kB
  • sloc: cpp: 142,035; sh: 109; ansic: 26; makefile: 12
file content (258 lines) | stat: -rw-r--r-- 6,130 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# REST Registry

The Glaze REST Registry automatically generates REST API endpoints from C++ classes using reflection. This eliminates boilerplate code and ensures consistency between your C++ domain models and REST APIs.

## Overview

The REST Registry:
- **Auto-generates** REST endpoints from C++ classes
- **Maps methods** to appropriate HTTP verbs (GET/POST/PUT/DELETE)  
- **Handles JSON** serialization/deserialization automatically
- **Validates input** using Glaze's JSON validation
- **Supports** complex nested objects and collections
- **Provides** type-safe API generation

> [!NOTE]
>
> Glaze's REST registry is actually format agnostic and can also be used with binary formats other than JSON.

## Quick Start

### Basic Service Registration

```cpp
#include "glaze/rpc/registry.hpp"
#include "glaze/net/http_server.hpp"

struct UserService {
    std::vector<User> getAllUsers() { 
        return users; 
    }
    
    User getUserById(int id) {
        // Find and return user
    }
    
    User createUser(const User& user) {
        // Create and return new user
    }
    
private:
    std::vector<User> users;
};

int main() {
    glz::http_server server;
    UserService userService;
    
    // Create REST registry
    glz::registry<glz::opts{}, glz::REST> registry;
    
    // Register service - auto-generates endpoints
    registry.on(userService);
    
    // Mount generated endpoints
    server.mount("/api", registry.endpoints);
    
    server.bind(8080).with_signals();
    server.start();
    server.wait_for_signal();
}
```

This automatically creates:
- `GET /api/getAllUsers` → `getAllUsers()`
- `POST /api/getUserById` → `getUserById(int)`  
- `POST /api/createUser` → `createUser(const User&)`

## Service Definition

### Method Types

The registry supports different method signatures:

```cpp
struct BookService {
    // No parameters - GET endpoint
    std::vector<Book> getAllBooks() {
        return books;
    }
    
    // Single parameter - POST endpoint with JSON body
    Book getBookById(int id) {
        return find_book(id);
    }
    
    // Object parameter - POST endpoint with object body
    Book createBook(const Book& book) {
        books.push_back(book);
        return book;
    }
    
    // Update method - PUT endpoint  
    Book updateBook(const BookUpdate& update) {
        auto& book = find_book(update.id);
        book.title = update.title;
        book.author = update.author;
        return book;
    }
    
    // Void return - POST endpoint, 204 No Content response
    void deleteBook(int id) {
        remove_book(id);
    }
    
private:
    std::vector<Book> books;
};
```

### Request/Response Objects

```cpp
// Domain objects for API
struct Book {
    int id;
    std::string title;
    std::string author;
    std::string isbn;
    int year;
};

struct BookUpdate {
    int id;
    std::string title;
    std::string author;
};

struct BookSearchRequest {
    std::string query;
    int limit = 10;
    int offset = 0;
};

struct BookSearchResponse {
    std::vector<Book> books;
    int total_count;
    bool has_more;
};
```

## HTTP Mapping

### Automatic Method Mapping

The registry maps C++ methods to HTTP verbs based on patterns:

| Method Pattern | HTTP Verb | Description |
|---------------|-----------|-------------|
| `get*()` | GET | Read operations, no parameters |
| `find*()` | GET | Read operations, no parameters |
| `list*()` | GET | Read operations, no parameters |
| `*()` with params | POST | Operations with input data |
| `create*()` | POST | Create operations |
| `update*()` | PUT | Update operations |
| `delete*()` | DELETE | Delete operations |

### Custom Mapping

```cpp
struct CustomService {
    // These all become POST endpoints due to parameters
    UserStats getUserStats(const StatsRequest& req) { /*...*/ }
    SearchResults searchUsers(const SearchQuery& query) { /*...*/ }
    ValidationResult validateUser(const User& user) { /*...*/ }
    
    // These become GET endpoints (no parameters)
    std::vector<User> getAllActiveUsers() { /*...*/ }
    ServerStatus getServerStatus() { /*...*/ }
    std::string getVersion() { /*...*/ }
};
```

## Advanced Features

### Error Handling

```cpp
struct SafeUserService {
    User getUserById(int id) {
        if (id <= 0) {
            throw std::invalid_argument("Invalid user ID");
        }
        
        auto it = users.find(id);
        if (it == users.end()) {
            throw std::runtime_error("User not found");
        }
        
        return it->second;
    }
    
    // Registry automatically converts exceptions to HTTP errors:
    // std::invalid_argument -> 400 Bad Request
    // std::runtime_error -> 500 Internal Server Error
    
private:
    std::unordered_map<int, User> users;
};
```

## Multiple Services

### Service Composition

```cpp
int main() {
    glz::http_server server;
    
    // Multiple service instances
    UserService userService;
    ProductService productService;
    OrderService orderService;
    
    // Single registry for all services
    glz::registry<glz::opts{}, glz::REST> registry;
    
    // Register all services
    registry.on(userService);
    registry.on(productService);  
    registry.on(orderService);
    
    // All endpoints available under /api
    server.mount("/api", registry.endpoints);
    
    server.bind(8080).with_signals();
    server.start();
    server.wait_for_signal();
}
```

## Customization

### Custom Serialization Options

```cpp
// Pretty JSON formatting
constexpr auto pretty_opts = glz::opts{.prettify = true};
glz::registry<pretty_opts, glz::REST> registry;
```

## API Documentation Generation

### Endpoint Discovery

```cpp
// Add endpoint listing for API discovery
server.get("/api", [&registry](const glz::request&, glz::response& res) {
    std::vector<std::string> endpoints;
    
    for (const auto& [path, methods] : registry.endpoints.routes) {
        for (const auto& [method, handler] : methods) {
            endpoints.push_back(glz::to_string(method) + " " + path);
        }
    }
    
    res.json({{"endpoints", endpoints}});
});
```