Skip to content

Commit 4003985

Browse files
Adds the CRUD API plugin. Closes #437 (#445)
1 parent 8a5d752 commit 4003985

File tree

5 files changed

+458
-0
lines changed

5 files changed

+458
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.DevProxy.Abstractions;
5+
using System.Text.Json;
6+
7+
namespace Microsoft.DevProxy.Plugins.MockResponses;
8+
9+
internal class CrudApiDefinitionLoader : IDisposable
10+
{
11+
private readonly ILogger _logger;
12+
private readonly CrudApiConfiguration _configuration;
13+
14+
public CrudApiDefinitionLoader(ILogger logger, CrudApiConfiguration configuration)
15+
{
16+
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
17+
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
18+
}
19+
20+
private FileSystemWatcher? _watcher;
21+
22+
public void LoadApiDefinition()
23+
{
24+
if (!File.Exists(_configuration.ApiFile))
25+
{
26+
_logger.LogWarn($"File {_configuration.ApiFile} not found. CRUD API will be disabled");
27+
return;
28+
}
29+
30+
try
31+
{
32+
using (FileStream stream = new FileStream(_configuration.ApiFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
33+
{
34+
using (StreamReader reader = new StreamReader(stream))
35+
{
36+
var apiDefinitionString = reader.ReadToEnd();
37+
var apiDefinitionConfig = JsonSerializer.Deserialize<CrudApiConfiguration>(apiDefinitionString);
38+
_configuration.BaseUrl = apiDefinitionConfig?.BaseUrl ?? string.Empty;
39+
_configuration.DataFile = apiDefinitionConfig?.DataFile ?? string.Empty;
40+
41+
IEnumerable<CrudApiAction>? configResponses = apiDefinitionConfig?.Actions;
42+
if (configResponses is not null)
43+
{
44+
_configuration.Actions = configResponses;
45+
foreach (var action in _configuration.Actions)
46+
{
47+
if (string.IsNullOrEmpty(action.Method))
48+
{
49+
action.Method = action.Action switch
50+
{
51+
CrudApiActionType.Create => "POST",
52+
CrudApiActionType.GetAll => "GET",
53+
CrudApiActionType.GetOne => "GET",
54+
CrudApiActionType.Merge => "PATCH",
55+
CrudApiActionType.Update => "PUT",
56+
CrudApiActionType.Delete => "DELETE",
57+
_ => throw new InvalidOperationException($"Unknown action type {action.Action}")
58+
};
59+
}
60+
}
61+
_logger.LogInfo($"{configResponses.Count()} actions for CRUD API loaded from {_configuration.ApiFile}");
62+
}
63+
}
64+
}
65+
}
66+
catch (Exception ex)
67+
{
68+
_logger.LogError($"An error has occurred while reading {_configuration.ApiFile}:");
69+
_logger.LogError(ex.Message);
70+
}
71+
}
72+
73+
public void InitApiDefinitionWatcher()
74+
{
75+
if (_watcher is not null)
76+
{
77+
return;
78+
}
79+
80+
string path = Path.GetDirectoryName(_configuration.ApiFile) ?? throw new InvalidOperationException($"{_configuration.ApiFile} is an invalid path");
81+
if (!File.Exists(_configuration.ApiFile))
82+
{
83+
_logger.LogWarn($"File {_configuration.ApiFile} not found. No CRUD API will be provided");
84+
_configuration.Actions = Array.Empty<CrudApiAction>();
85+
return;
86+
}
87+
88+
_watcher = new FileSystemWatcher(Path.GetFullPath(path))
89+
{
90+
NotifyFilter = NotifyFilters.CreationTime
91+
| NotifyFilters.FileName
92+
| NotifyFilters.LastWrite
93+
| NotifyFilters.Size,
94+
Filter = Path.GetFileName(_configuration.ApiFile),
95+
EnableRaisingEvents = true
96+
};
97+
_watcher.Changed += ApiDefinitionFile_Changed;
98+
_watcher.Created += ApiDefinitionFile_Changed;
99+
_watcher.Deleted += ApiDefinitionFile_Changed;
100+
_watcher.Renamed += ApiDefinitionFile_Changed;
101+
102+
LoadApiDefinition();
103+
}
104+
105+
private void ApiDefinitionFile_Changed(object sender, FileSystemEventArgs e)
106+
{
107+
LoadApiDefinition();
108+
}
109+
110+
public void Dispose()
111+
{
112+
_watcher?.Dispose();
113+
}
114+
}

0 commit comments

Comments
 (0)