1 /**
2  * Methods to generate `severs.d`, which allows control over the servers used to contact the API.
3  */
4 module openapi_client.servers;
5 
6 import std.array : appender, split, Appender;
7 import std.file : mkdir, mkdirRecurse, write;
8 import std.path : buildNormalizedPath, dirName;
9 import std.string : tr;
10 
11 import openapi : OasDocument, OasServer, OasServerVariable;
12 import openapi_client.util : wordWrapText, toUpperCamelCase;
13 
14 /**
15  * Writes a utility class containing information about the REST API servers to contact.
16  */
17 void writeServerFiles(OasDocument oasDocument, string targetDir, string packageRoot) {
18   auto buffer = appender!string();
19   string moduleName = packageRoot ~ ".servers";
20   with (buffer) {
21     put("// File automatically generated from OpenAPI spec.\n");
22     put("module " ~ moduleName ~ ";\n\n");
23     put("import openapi_client.util : resolveTemplate;\n");
24     put("import std.stdio : writeln;\n");
25     put("\n");
26     put("class Servers {\n");
27     // For now, only support a single URL, because it is unclear what to do if each server has
28     // different parameters.
29     put("  /**\n");
30     put("   * The server URLs to contact the service with.\n");
31     put("   * The URL may use named path-parameters within curly braces,\n");
32     put("   * e.g. \"https://example.com/{version}/\".\n");
33     put("   */\n");
34     put("  static string serverUrl = \"");
35     put(oasDocument.servers[0].url);
36     put("\";\n\n");
37 
38     // Parameters that will be substituted into the serverURL.
39     put("  /**\n");
40     put("   * Parameters that will be substituted into the serverURL.\n");
41     put("   */\n");
42     put("  static string[string] serverParams;\n\n");
43     put("  static this() {\n");
44     put("    serverParams = [\n");
45     put("      \"none\": \"none\",\n");
46     foreach (string name, OasServerVariable variable; oasDocument.servers[0].variables) {
47       put("      \"" ~ name ~ "\": \"" ~ variable.default_ ~ "\",\n");
48     }
49     put("    ];\n");
50     put("  }\n\n");
51     // Documented methods to set the values for these parameters.
52     foreach (string name, OasServerVariable variable; oasDocument.servers[0].variables) {
53       put("  /**\n");
54       put("   * Server URL Parameter: " ~ name ~ "\n");
55       foreach (string line; wordWrapText(variable.description, 95)) {
56         put("   * ");
57         put(line);
58         put("\n");
59       }
60       put("   * Valid values include:\n");
61       foreach (string validValue; variable.enum_) {
62         put("   * - " ~ validValue ~ "\n");
63       }
64       put("   */\n");
65       put("  static void setParam" ~ toUpperCamelCase(name) ~ "(string value) {\n");
66       put("    serverParams[\"" ~ name ~ "\"] = value;\n");
67       put("  }\n\n");
68     }
69     // Resolve the server URL using the current values of its parameters.
70     put("  /**\n");
71     put("   * Chooses a url an OasPathItem given both path-specific and general servers.\n");
72     put("   */\n");
73     put("  static string getServerUrl() {\n");
74     put("    return resolveTemplate(serverUrl, serverParams);\n");
75     put("  }\n\n");
76     put("}\n");
77   }
78   string fileName = buildNormalizedPath(targetDir, tr(moduleName, ".", "/") ~ ".d");
79   mkdirRecurse(dirName(fileName));
80   write(fileName, buffer[]);
81 }