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
|
# Anope REST API
Anope provides a RESTful HTTP API through the rest and httpd modules which
expose basic CRUD operations on all of Anope's internal data structures.
The type names and data structures are the same as is used in the SQL/RDBMS
databaes support, but it otherwise currently not documented.
The RESTful API documented here is relatively low level and allows you to
construct things that aren't normally possible in Anope, such as creating
nickless accounts or having an accounts display not matched a grouped nicks
name. This would produce weird behavior and not work as expected. It is
your responsibility to not do this.
As an alternative you may execute commands remotely using the xmlrpc_main
module, which uses Anope's normal command system and is less subject to misuse.
# Example usage
## Getting available object types
```
$ curl localhost:8080/rest/types
{
"types": [
"botinfo",
"xline",
"oper",
"badword",
"channel",
"level",
"mlockmode",
"accesschanaccess",
"akick",
"entrymsg",
"flagschanaccess",
"logsetting",
"modelock",
"csmiscdata",
"cssuspendinfo",
"xopchanaccess",
"vhost",
"hostrequest",
"memoinfo",
"memo",
"memoignore",
"nick",
"account",
"mode",
"nsaccess",
"autojoin",
"nsmiscdata",
"nssuspendinfo",
"forbid",
"ignore",
"operinfo",
"newsitem",
"exception",
"stats"
]
}
```
The types are subject to change, as several are dynamically added via modules,
including third party modules.
## Listing objects of a type
Send a GET to /rest/{object type} to return a list of all objects of that type.
For example, to fetch a list of all accounts.
```
$ curl localhost:8080/rest/account
{
"account": [
{
"display": "Adam",
"pass": "sha256:55ad6396a287df38967de578cbf92788faea8c94cd7d0e4f55eb45257921d75b:3df6978927389fb71a560a232572e5871bd072752eca27f159dc1fdc2462411c",
"email": "adam@sigterm.info",
"id": "10"
},
{
"display": "Adam2",
"pass": "sha256:4cbb6ec03a8e7401342ee8832f5e4bd2abeb8fc7a007e66e2ac02e0c14f694f0:041167d04d70381e4218781e06b2b57b08165a987aced63f0a8ca8d25ac8ee51",
"email": "adam@anope.org",
"id": "95"
}
]
}
```
## Searching for objects
You may search for objects by the value of one of their fields, if it is unique.
This is most useful for looking up nicks, accounts, and channels.
If the field you are searching for is not something commonly looked up by Anope,
which is mostly anything other than nick, account, and channel names, it will
likely cause the SQL database backend to on-the-fly index the field.
Send a GET request to /rest/{object type}/{field name}/{search}
```
$ curl localhost:8080/rest/account/display/Adam
{
"display": "Adam",
"pass": "sha256:55ad6396a287df38967de578cbf92788faea8c94cd7d0e4f55eb45257921d75b:3df6978927389fb71a560a232572e5871bd072752eca27f159dc1fdc2462411c",
"email": "adam@sigterm.info",
"id": "10"
}
```
Which will return the entire object. If it is not found, a non-200 status code is returned,
along with an error message. Error messages are never JSON formatted, but are simple strings.
## Getting objects
If you have an object ID, you can also fetch the object by id.
Send a GET request to /rest/{object type}/{id}
```
$ curl localhost:8080/rest/account/10
{
"display": "Adam",
"pass": "sha256:55ad6396a287df38967de578cbf92788faea8c94cd7d0e4f55eb45257921d75b:3df6978927389fb71a560a232572e5871bd072752eca27f159dc1fdc2462411c",
"email": "adam@sigterm.info",
"id": "10"
}
```
## Updating the value of a field of an existing object
You may PUT to /rest/{object type}/{id}/{field} data to update the value of a field.
```
$ curl -D - -X PUT localhost:8080/rest/account/10/email -d 'adam@anope.org'
HTTP/1.1 200 OK
Date: Sun, 30 Oct 2016 17:17:05 EDT
Server: Anope-2.1
Content-Type: application/json
Content-Length: 0
Connection: Close
```
Again, a 200 status code is okay, anything else is an error, and a description is provided in the reply content.
You can now fetch the object back and notice the changed email address.
## Creating objects
You can create new objects by POSTing to /rest/{object type}
```
$ curl -D - -X POST localhost:8080/rest/account -d '{"display": "Adam3", "email": "Adam@anope.org"}'
HTTP/1.1 201 Created
Date: Sun, 30 Oct 2016 17:39:56 EDT
Server: Anope-2.1
Content-Type: application/json
Content-Length: 3
Connection: Close
126
```
This will return a 201 Ceated, with the body being the object's new id.
## Deleting objects
Similarly you can delete objects by sending DELETE to /rest/{object type}/{id}.
```
$ curl -D - -X DELETE localhost:8080/rest/account/126
HTTP/1.1 200 OK
Date: Sun, 30 Oct 2016 17:42:40 EDT
Server: Anope-2.1
Content-Type: application/json
Content-Length: 0
Connection: Close
```
Due to the way Anope stores its data, deleting any object at any time should be safe, and will not leak
other (perhaps now unreachable) objects.
# Object References and Relationships
Object references are represented in the REST API by {type}:{id}
```
$ curl localhost:8080/rest/nsaccess/13
{
"account": "account:10",
"mask": "Adam@*.gvd.168.192.IP",
"id": "13"
}
```
Such as the value of "account" here for this nickserv access entry. Even though object ids within Anope
are global and not specific to the type. As such, if you submit a POST or PUT operation which creates a
field that is a reference, it is expected you supply both the type and id, in this format.
It is possible to search for object references of a specific type to a given object. This is how all
one-to-many relationships are looked up within Anope. Objects never contain lists of other objects.
There are no join tables, and the objects within the C++ API do not contain collections of other
objects.
For example:
```
$ curl localhost:8080/rest/account/10?refs=nsaccess
{
"account": [
{
"account": "account:10",
"mask": "Adam@*.gvd.168.192.IP",
"id": "13"
},
{
"account": "account:10",
"mask": "adam@anope.org",
"id": "126"
}
]
}
```
This fetches all objects of type nsaccess which have a reference to an account with id 10. Because
the type nsaccess only has one field that is a reference, the result is effectively the account's
NickServ access list.
Because searching by refs searches object references and not at a field level, in cases of searching
for objects with mutltiple references, you would have to inspect the resulting objects to see if it
is what you want. For example, if you wanted to find all channels owned by a user, you may perform
something like GET /rest/account/10?refs=channel. The channels returned have a reference to the
given account, whether that is the channels founder or something else, like successor, or any other
field possible (that may have even been added by a 3rd party module), is unknown.
Relationships defined within Anope, that is, the fields on objects which are object references, can
optionally depend on the existance of the object to which they reference. These fields can be seen
within the SQL schema as having foreign keys with ON CASCADE DELETE. When an object is deleted, all
references to it automatically get either NULLed, or the objects which reference it get recursively
deleted too. This is why it is generally safe to delete any object at any time.
The field "account" on "nsaccess" is one that will cascade delete, which is why if you delete an
account, the access entries for it are automatically also cleaned up.
|