-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRestapi.cs
More file actions
122 lines (117 loc) · 4.24 KB
/
Restapi.cs
File metadata and controls
122 lines (117 loc) · 4.24 KB
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
using System.IO;
using System.Reflection;
namespace Webtech3;
/// <summary>
/// Delegate for wrap endpoint implementation functions.
/// Functions must be async.
/// </summary>
/// <param name="req">Request data</param>
/// <param name="res">Response data</param>
/// <returns>Task obj</returns>
public delegate Task APIAction(Request req, Response res);
internal record APIEndpoint(APIInfo Info, APIAction Action);
/// <summary>
/// Class, that makes whole api on the functions set
/// </summary>
public sealed class RestAPI {
private static APIInfo ExtractAPIInfo(MethodInfo m)
=> m.GetCustomAttribute<APIInfo>()
?? throw new Exception($"Endpoint {m.Name} hasn't API info.");
internal APIEndpoint? this[HTTP.Methods method, string url] {
get => endpoints.FirstOrDefault(
ep => ep.Info.IsMatch(url, method)
);
}
readonly List<APIEndpoint> endpoints;
/// <summary>
/// Construct API instance without endpoints
/// </summary>
public RestAPI() {
endpoints = new();
}
/// <summary>
/// Construct API instance with endpoints from static methods of given class
/// </summary>
/// <param name="APIimpl">Type of class, that implements api endpoints</param>
public RestAPI(Type APIimpl) {
endpoints = new(
from m in APIimpl.GetMethods()
where m.IsStatic
select new APIEndpoint(
ExtractAPIInfo(m), m.CreateDelegate<APIAction>()
)
);
}
/// <summary>
/// Routes endpoint without APIinfo attr
/// </summary>
/// <param name="url">URL for endpoint</param>
/// <param name="action">APIaction delegate from endpoint function</param>
/// <param name="auth">Flag meaning need or not do auth</param>
/// <param name="roles">Roles array for filter access to endpoint</param>
/// <param name="methods">Array of HTTP methods for endpoint</param>
public void Route(
string url,
APIAction action,
bool auth = false,
byte[]? roles = null,
HTTP.Methods[]? methods = null
) => endpoints.Add(new(
new APIInfo(url, auth, methods, roles),
action
)
);
/// <summary>
/// Adding simply endpoint to API.
/// Function must have a APIinfo attr.
/// </summary>
/// <param name="action">APIaction delegate instance from function</param>
public void Add(APIAction action) => endpoints.Add(new(
ExtractAPIInfo(action.Method),
action
)
);
/// <summary>
/// Disable endpoint by URL and method.
/// </summary>
/// <param name="url">URL of endpoint</param>
/// <param name="method">HTTP method of endpoint</param>
public void DisableEndpoint(string url, HTTP.Methods method) {
var ep = this[method, url];
if (ep is not null) {
endpoints.Remove(ep);
}
}
/// <summary>
/// Map current API to file.
/// </summary>
/// <param name="path">Path for output file</param>
/// <returns>Task obj</returns>
public async Task MapAPI(string path) {
using var fs = new FileStream(path, FileMode.Create);
using var writer = new StreamWriter(fs);
foreach(var ep in endpoints)
await writer.WriteLineAsync(
$"""
{ep.Action.Method.Name}:
URL regex pattern: {ep.Info.Url}
Methods: {string.Join(", ", ep.Info.Methods)}
Auth: {(ep.Info.Authentication ? "Required" : "Not required")}
Roles: {(ep.Info.Roles is null ? "Any" : string.Join(", ", ep.Info.Roles))}
Description: {ep.Info.Description?.Trim() ?? "No description specified"}
"""
);
}
IAuthManager? auther;
/// <summary>
/// Property for get/set obj, implements IAuthManager
/// </summary>
/// <value>Instance of class, that implements IAuthManager or null</value>
/// <exception cref="Exception">
/// Just exception with message if you trying set auth-or null
/// </exception>
public IAuthManager? Authentificator {
get => auther;
set => auther = value ?? throw new Exception("Not allowed to set null for Authentificator.");
}
}