├── .cursor └── rules │ └── generators.mdc ├── .github └── workflows │ └── build.yml ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── examples.md ├── jest.config.js ├── package-lock.json ├── package.json ├── src ├── code.ts ├── generator.ts ├── generators │ ├── clojure.test.ts │ ├── clojure.ts │ ├── csharp.test.ts │ ├── csharp.ts │ ├── curl.test.ts │ ├── curl.ts │ ├── dart.test.ts │ ├── dart.ts │ ├── elixir.test.ts │ ├── elixir.ts │ ├── go.test.ts │ ├── go.ts │ ├── java.test.ts │ ├── java.ts │ ├── javascript.test.ts │ ├── javascript.ts │ ├── kotlin.test.ts │ ├── kotlin.ts │ ├── node-axios.test.ts │ ├── node-axios.ts │ ├── node-fetch.test.ts │ ├── node-fetch.ts │ ├── node-http.test.ts │ ├── node-http.ts │ ├── objective-c.test.ts │ ├── objective-c.ts │ ├── php-guzzle.test.ts │ ├── php-guzzle.ts │ ├── php-requests.test.ts │ ├── php-requests.ts │ ├── php.test.ts │ ├── php.ts │ ├── python-requests.test.ts │ ├── python-requests.ts │ ├── python.test.ts │ ├── python.ts │ ├── ruby.test.ts │ ├── ruby.ts │ ├── rust.test.ts │ ├── rust.ts │ ├── swift.test.ts │ ├── swift.ts │ ├── wget.test.ts │ └── wget.ts ├── request.ts ├── scripts │ └── examples.ts └── target.ts └── tsconfig.json /.cursor/rules/generators.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | alwaysApply: true 5 | --- 6 | # Code Examples Generators 7 | 8 | All code generators should follow the next rules: 9 | 10 | 1. They don't produce code with comments. 11 | 2. They should generate idiomatic code for their target lanuage. 12 | 3. The should not try to extract data from response, but in the code example, the response variable should be the last one. 13 | 4. They should generate compact and elegant code. But with new lines, no need to pack everything in one line. 14 | 5. If the options body is a JSON body, it should be a dictionary object formatted properly and be ready to accept big JSON. Put properties on new line each. 15 | 6. And the same for query parameters (as for JSON): it should be a dictionary object formatted properly and be ready to accept many parameters and some of them can be an array even, put them on new line each. -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | node-version: [16.x, 17.x, 18.x] 17 | 18 | steps: 19 | - uses: actions/checkout@v3 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v3 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | - run: npm install 25 | - run: npm run build --if-present 26 | - run: npm run test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.swp 10 | 11 | pids 12 | logs 13 | results 14 | tmp 15 | 16 | # Build 17 | public/css/main.css 18 | 19 | # Coverage reports 20 | coverage 21 | 22 | # API keys and secrets 23 | .env 24 | 25 | # Dependency directory 26 | node_modules 27 | bower_components 28 | 29 | # Editors 30 | .idea 31 | *.iml 32 | 33 | # OS metadata 34 | .DS_Store 35 | Thumbs.db 36 | 37 | # Ignore built ts files 38 | dist/**/* 39 | 40 | # ignore yarn.lock 41 | yarn.lock -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.swp 10 | 11 | pids 12 | logs 13 | results 14 | tmp 15 | 16 | # Build 17 | public/css/main.css 18 | 19 | # Coverage reports 20 | coverage 21 | 22 | # API keys and secrets 23 | .env 24 | 25 | # Dependency directory 26 | node_modules 27 | bower_components 28 | 29 | # Editors 30 | .idea 31 | *.iml 32 | 33 | # OS metadata 34 | .DS_Store 35 | Thumbs.db 36 | 37 | # ignore yarn.lock 38 | yarn.lock -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2023 Dmytro Krasun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 21 | OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # requestcodegen 2 | 3 | [![Build](https://github.com/krasun/requestcodegen/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/krasun/requestcode/actions/workflows/build.yml) 4 | [![NPM package](https://img.shields.io/npm/v/requestcodegen.svg?branch=main)](https://www.npmjs.com/package/requestcodegen) 5 | 6 | `requestcodegen` is a library to generate HTTP client example code in different programming languages. 7 | 8 | ## Install 9 | 10 | ```shell 11 | npm install requestcodegen --save 12 | ``` 13 | 14 | ## Use 15 | 16 | Using the library is as easy as: 17 | 18 | ```typescript 19 | import { generateCode } from "requestcodegen"; 20 | 21 | const clojureCodeExample = generateCode( 22 | { url: "http://example.com", method: "POST" }, 23 | CodeTarget.Clojure 24 | ); 25 | ``` 26 | 27 | ## Build and publish (a manual for developers) 28 | 29 | To build and publish the library: 30 | 31 | 1. Bump the version property in the `package.json` file. 32 | 2. Run `npm run prepare`. 33 | 3. Run `npm publish`. 34 | 35 | ## Code Examples 36 | 37 | Check out examples of generated code in the [examples.md](examples.md) file. 38 | 39 | # Known usages 40 | 41 | A few examples of how the library is used: 42 | 43 | 1. [ScreenshotOne](https://screenshotone.com) uses the library for generating code examples in the playground for the screenshot API. 44 | 45 | If you use the library, please, don't hesitate to share how and in what project. 46 | 47 | ## License 48 | 49 | `krasun/requestcodegen` is released under [the MIT license](LICENSE). 50 | -------------------------------------------------------------------------------- /examples.md: -------------------------------------------------------------------------------- 1 | # Code Examples 2 | 3 | ## Clojure (POST) 4 | 5 | ```Clojure 6 | (ns my.namespace 7 | (:require [clj-http.client :as client])) 8 | 9 | (defn make-request [] 10 | (client/request 11 | { 12 | :url "http://example.com" 13 | :method :post 14 | :headers {"Content-Type" "application/json"} 15 | :body {"name" "John Doe" 16 | "baz" ["qux" "quix"]}})) 17 | 18 | ``` 19 | 20 | ## Clojure (GET) 21 | 22 | ```Clojure 23 | (ns my.namespace 24 | (:require [clj-http.client :as client])) 25 | 26 | (defn make-request [] 27 | (client/request 28 | { 29 | :url "http://example.com" 30 | :query-params {"baz" ["qux" "quix"] 31 | "foo" "bar"} 32 | :method :get})) 33 | 34 | ``` 35 | 36 | ## C# (POST) 37 | 38 | ```CSharp 39 | using System; 40 | using System.Net.Http; 41 | using System.Threading.Tasks; 42 | using System.Text.Json; 43 | 44 | public class Program { 45 | public static async Task Main(string[] args) { 46 | using var client = new HttpClient(); 47 | var requestData = new { 48 | name = "John Doe", 49 | baz = new object[] { 50 | "qux", 51 | "quix" 52 | } 53 | }; 54 | 55 | var request = new HttpRequestMessage { 56 | Method = new HttpMethod("POST"), 57 | RequestUri = new Uri("http://example.com") 58 | }; 59 | request.Headers.Add("Content-Type", "application/json"); 60 | 61 | var jsonOptions = new JsonSerializerOptions { 62 | }; 63 | request.Content = new StringContent( 64 | JsonSerializer.Serialize(requestData, jsonOptions), 65 | System.Text.Encoding.UTF8, 66 | "application/json" 67 | ); 68 | 69 | try { 70 | using var response = await client.SendAsync(request); 71 | response.EnsureSuccessStatusCode(); 72 | } catch (Exception ex) { 73 | Console.WriteLine(ex.ToString()); 74 | } 75 | } 76 | } 77 | ``` 78 | 79 | ## C# (GET) 80 | 81 | ```CSharp 82 | using System; 83 | using System.Net.Http; 84 | using System.Threading.Tasks; 85 | using System.Text.Json; 86 | 87 | public class Program { 88 | public static async Task Main(string[] args) { 89 | using var client = new HttpClient(); 90 | var request = new HttpRequestMessage { 91 | Method = new HttpMethod("GET"), 92 | RequestUri = new Uri("http://example.com") 93 | }; 94 | 95 | 96 | var query = System.Web.HttpUtility.ParseQueryString(string.Empty); 97 | query["baz"] = "qux"; 98 | query["baz"] = "quix"; 99 | query["foo"] = "bar"; 100 | request.RequestUri = new Uri(request.RequestUri + "?" + query); 101 | try { 102 | using var response = await client.SendAsync(request); 103 | response.EnsureSuccessStatusCode(); 104 | } catch (Exception ex) { 105 | Console.WriteLine(ex.ToString()); 106 | } 107 | } 108 | } 109 | ``` 110 | 111 | ## curl (POST) 112 | 113 | ```Curl 114 | curl -X POST 'http://example.com' -H 'Content-Type: application/json' -d '{"name":"John Doe","baz":["qux","quix"]}' 115 | ``` 116 | 117 | ## curl (GET) 118 | 119 | ```Curl 120 | curl -X GET 'http://example.com?baz=qux,quix&foo=bar' 121 | ``` 122 | 123 | ## Dart (POST) 124 | 125 | ```Dart 126 | import 'dart:convert'; 127 | import 'package:http/http.dart' as http; 128 | 129 | Future request() async { 130 | final url = Uri.parse('http://example.com'); 131 | 132 | final options = { 133 | "name": "John Doe", 134 | "baz": [ 135 | "qux", 136 | "quix" 137 | ] 138 | }; 139 | 140 | final response = await http.post( 141 | url, 142 | headers: { 143 | "Content-Type": "application/json" 144 | }, 145 | body: jsonEncode(options) 146 | ); 147 | 148 | if (response.statusCode != 200) { 149 | throw Exception('Request failed with status: ${response.statusCode}'); 150 | } 151 | 152 | // process response 153 | } 154 | ``` 155 | 156 | ## Dart (GET) 157 | 158 | ```Dart 159 | import 'dart:convert'; 160 | import 'package:http/http.dart' as http; 161 | 162 | Future request() async { 163 | final url = Uri.parse('http://example.com'); 164 | final queryParameters = { 165 | "baz": [ 166 | "qux", 167 | "quix" 168 | ], 169 | "foo": "bar" 170 | }; 171 | final urlWithQuery = url.replace(queryParameters: queryParameters); 172 | 173 | final response = await http.get( 174 | urlWithQuery 175 | ); 176 | 177 | if (response.statusCode != 200) { 178 | throw Exception('Request failed with status: ${response.statusCode}'); 179 | } 180 | 181 | // process response 182 | } 183 | ``` 184 | 185 | ## Elixir (POST) 186 | 187 | ```Elixir 188 | defmodule Example do 189 | use HTTPoison.Base 190 | 191 | def request do 192 | url = "http://example.com" 193 | headers = %{ 194 | "Content-Type": "application/json" 195 | } 196 | params = %{} 197 | body = %{ 198 | "name": "John Doe", 199 | "baz": ["qux","quix"] 200 | } 201 | 202 | response = HTTPoison.post!(url, body, headers, params: params) 203 | end 204 | end 205 | ``` 206 | 207 | ## Elixir (GET) 208 | 209 | ```Elixir 210 | defmodule Example do 211 | use HTTPoison.Base 212 | 213 | def request do 214 | url = "http://example.com" 215 | headers = %{} 216 | params = %{ 217 | "baz": ["qux","quix"], 218 | "foo": "bar" 219 | } 220 | body = nil 221 | 222 | response = HTTPoison.get!(url, headers, params: params) 223 | end 224 | end 225 | ``` 226 | 227 | ## Go (POST) 228 | 229 | ```Go 230 | package main 231 | 232 | import ( 233 | "bytes" 234 | "fmt" 235 | "io" 236 | "net/http" 237 | "net/url" 238 | ) 239 | 240 | func main() { 241 | client := &http.Client{} 242 | 243 | url := "http://example.com" 244 | method := "POST" 245 | 246 | var req *http.Request 247 | var err error 248 | 249 | jsonBody := `{ 250 | "name": "John Doe", 251 | "baz": [ 252 | "qux", 253 | "quix" 254 | ] 255 | }` 256 | req, err = http.NewRequest(method, url, bytes.NewBufferString(jsonBody)) 257 | if err != nil { 258 | fmt.Println(err) 259 | return 260 | } 261 | 262 | req.Header.Add("Content-Type", "application/json") 263 | 264 | resp, err := client.Do(req) 265 | if err != nil { 266 | fmt.Println(err) 267 | return 268 | } 269 | defer resp.Body.Close() 270 | } 271 | ``` 272 | 273 | ## Go (GET) 274 | 275 | ```Go 276 | package main 277 | 278 | import ( 279 | "bytes" 280 | "fmt" 281 | "io" 282 | "net/http" 283 | "net/url" 284 | ) 285 | 286 | func main() { 287 | client := &http.Client{} 288 | 289 | url := "http://example.com" 290 | method := "GET" 291 | 292 | var req *http.Request 293 | var err error 294 | 295 | req, err = http.NewRequest(method, url, nil) 296 | if err != nil { 297 | fmt.Println(err) 298 | return 299 | } 300 | 301 | params := url.Values{} 302 | params.Add("baz", "qux") 303 | params.Add("baz", "quix") 304 | params.Add("foo", "bar") 305 | req.URL.RawQuery = params.Encode() 306 | 307 | resp, err := client.Do(req) 308 | if err != nil { 309 | fmt.Println(err) 310 | return 311 | } 312 | defer resp.Body.Close() 313 | } 314 | ``` 315 | 316 | ## Java (POST) 317 | 318 | ```Java 319 | import java.io.BufferedReader; 320 | import java.io.InputStreamReader; 321 | import java.io.OutputStream; 322 | import java.net.HttpURLConnection; 323 | import java.net.URL; 324 | import java.net.URLEncoder; 325 | import java.nio.charset.StandardCharsets; 326 | import java.util.LinkedHashMap; 327 | import java.util.Map; 328 | 329 | public class Main { 330 | public static void main(String[] args) throws Exception { 331 | Map params = new LinkedHashMap<>(); 332 | 333 | 334 | StringBuilder urlBuilder = new StringBuilder("http://example.com"); 335 | if (!params.isEmpty()) { 336 | urlBuilder.append("?"); 337 | boolean first = true; 338 | for (Map.Entry entry : params.entrySet()) { 339 | if (!first) { 340 | urlBuilder.append("&"); 341 | } 342 | urlBuilder.append(URLEncoder.encode(entry.getKey(), "UTF-8")); 343 | urlBuilder.append("="); 344 | urlBuilder.append(URLEncoder.encode(entry.getValue(), "UTF-8")); 345 | first = false; 346 | } 347 | } 348 | 349 | HttpURLConnection conn = (HttpURLConnection) new URL(urlBuilder.toString()).openConnection(); 350 | conn.setRequestMethod("POST"); 351 | conn.setRequestProperty("Content-Type", "application/json"); 352 | 353 | conn.setDoOutput(true); 354 | try (OutputStream os = conn.getOutputStream()) { 355 | byte[] input = String.format( 356 | { 357 | "name": "John Doe", 358 | "baz": [ 359 | "qux", 360 | "quix" 361 | ] 362 | } 363 | ).getBytes("utf-8"); 364 | os.write(input, 0, input.length); 365 | } 366 | 367 | StringBuilder response = new StringBuilder(); 368 | try (BufferedReader br = new BufferedReader(new InputStreamReader( 369 | conn.getResponseCode() >= 400 ? conn.getErrorStream() : conn.getInputStream()))) { 370 | String line; 371 | while ((line = br.readLine()) != null) { 372 | response.append(line); 373 | } 374 | } 375 | conn.disconnect(); 376 | } 377 | } 378 | 379 | ``` 380 | 381 | ## Java (GET) 382 | 383 | ```Java 384 | import java.io.BufferedReader; 385 | import java.io.InputStreamReader; 386 | import java.io.OutputStream; 387 | import java.net.HttpURLConnection; 388 | import java.net.URL; 389 | import java.net.URLEncoder; 390 | import java.nio.charset.StandardCharsets; 391 | import java.util.LinkedHashMap; 392 | import java.util.Map; 393 | 394 | public class Main { 395 | public static void main(String[] args) throws Exception { 396 | Map params = new LinkedHashMap<>(); 397 | params.add("baz", "qux"); 398 | params.add("baz", "quix"); 399 | params.add("foo", "bar"); 400 | 401 | StringBuilder urlBuilder = new StringBuilder("http://example.com"); 402 | if (!params.isEmpty()) { 403 | urlBuilder.append("?"); 404 | boolean first = true; 405 | for (Map.Entry entry : params.entrySet()) { 406 | if (!first) { 407 | urlBuilder.append("&"); 408 | } 409 | urlBuilder.append(URLEncoder.encode(entry.getKey(), "UTF-8")); 410 | urlBuilder.append("="); 411 | urlBuilder.append(URLEncoder.encode(entry.getValue(), "UTF-8")); 412 | first = false; 413 | } 414 | } 415 | 416 | HttpURLConnection conn = (HttpURLConnection) new URL(urlBuilder.toString()).openConnection(); 417 | conn.setRequestMethod("GET"); 418 | 419 | 420 | 421 | StringBuilder response = new StringBuilder(); 422 | try (BufferedReader br = new BufferedReader(new InputStreamReader( 423 | conn.getResponseCode() >= 400 ? conn.getErrorStream() : conn.getInputStream()))) { 424 | String line; 425 | while ((line = br.readLine()) != null) { 426 | response.append(line); 427 | } 428 | } 429 | conn.disconnect(); 430 | } 431 | } 432 | 433 | ``` 434 | 435 | ## JavaScript (POST) 436 | 437 | ```JavaScript 438 | const params = new URLSearchParams({ 439 | }); 440 | 441 | const requestOptions = { 442 | method: 'POST', 443 | headers: { 444 | 'Content-Type': 'application/json' 445 | }, 446 | body: { 447 | "name": "John Doe", 448 | "baz": [ 449 | "qux", 450 | "quix" 451 | ] 452 | }, 453 | }; 454 | 455 | const response = await fetch('http://example.com' + '?' + params.toString(), requestOptions); 456 | 457 | ``` 458 | 459 | ## JavaScript (GET) 460 | 461 | ```JavaScript 462 | const params = new URLSearchParams({ 463 | baz: 'qux', 464 | baz: 'quix', 465 | foo: 'bar' 466 | }); 467 | 468 | const requestOptions = { 469 | method: 'GET', 470 | }; 471 | 472 | const response = await fetch('http://example.com' + '?' + params.toString(), requestOptions); 473 | 474 | ``` 475 | 476 | ## Kotlin (POST) 477 | 478 | ```Kotlin 479 | import java.net.URL 480 | import java.net.HttpURLConnection 481 | import com.google.gson.Gson 482 | 483 | fun makeRequest() { 484 | val gson = Gson() 485 | val params = mutableMapOf() 486 | 487 | val url = URL("http://example.com") 488 | val connection = url.openConnection() as HttpURLConnection 489 | connection.requestMethod = "POST" 490 | connection.setRequestProperty("Content-Type", "application/json") 491 | val requestBody = mapOf( 492 | "name" to "John Doe", 493 | "baz" to "qux,quix" 494 | ) 495 | val jsonBody = gson.toJson(requestBody) 496 | connection.setRequestProperty("Content-Type", "application/json") 497 | connection.outputStream.use { os -> 498 | os.write(jsonBody.toByteArray()) 499 | } 500 | val response = connection.inputStream.bufferedReader().use { it.readText() } 501 | val responseCode = connection.responseCode 502 | if (responseCode != HttpURLConnection.HTTP_OK) { 503 | throw RuntimeException("HTTP error code: $responseCode") 504 | } 505 | } 506 | ``` 507 | 508 | ## Kotlin (GET) 509 | 510 | ```Kotlin 511 | import java.net.URL 512 | import java.net.HttpURLConnection 513 | import com.google.gson.Gson 514 | 515 | fun makeRequest() { 516 | val gson = Gson() 517 | val params = mutableMapOf() 518 | params["baz"] = "qux" 519 | params["baz"] = "quix" 520 | params["foo"] = "bar" 521 | val url = URL("http://example.com?${params.entries.joinToString("&") { "${it.key}=${it.value}" }}") 522 | val connection = url.openConnection() as HttpURLConnection 523 | connection.requestMethod = "GET" 524 | 525 | 526 | val response = connection.inputStream.bufferedReader().use { it.readText() } 527 | val responseCode = connection.responseCode 528 | if (responseCode != HttpURLConnection.HTTP_OK) { 529 | throw RuntimeException("HTTP error code: $responseCode") 530 | } 531 | } 532 | ``` 533 | 534 | ## Node (HTTP) (POST) 535 | 536 | ```NodeHTTP 537 | const http = require('http'); 538 | const body = { 539 | name: "John Doe", 540 | baz: ["qux","quix"] 541 | }; 542 | 543 | const options = { 544 | hostname: 'example.com', 545 | port: 80, 546 | path: '/', 547 | method: 'POST', 548 | headers: {"Content-Type":"application/json"} 549 | }; 550 | 551 | let response = ''; 552 | const req = http.request(options, (res) => { 553 | res.on('data', (chunk) => { 554 | response += chunk; 555 | }); 556 | }); 557 | 558 | req.on('error', (error) => { 559 | console.error(error); 560 | }); 561 | 562 | req.write(JSON.stringify(body)); 563 | req.end(); 564 | ``` 565 | 566 | ## Node (HTTP) (GET) 567 | 568 | ```NodeHTTP 569 | const http = require('http'); 570 | const querystring = require('querystring'); 571 | const query = { 572 | baz: ["qux","quix"], 573 | foo: "bar" 574 | }; 575 | 576 | const options = { 577 | hostname: 'example.com', 578 | port: 80, 579 | path: '/' + '?' + querystring.stringify(query), 580 | method: 'GET', 581 | headers: {} 582 | }; 583 | 584 | let response = ''; 585 | const req = http.request(options, (res) => { 586 | res.on('data', (chunk) => { 587 | response += chunk; 588 | }); 589 | }); 590 | 591 | req.on('error', (error) => { 592 | console.error(error); 593 | }); 594 | 595 | req.end(); 596 | ``` 597 | 598 | ## Node (Axios) (POST) 599 | 600 | ```NodeAxios 601 | const axios = require('axios'); 602 | 603 | axios({ 604 | method: 'POST', 605 | url: 'http://example.com', 606 | headers: { 607 | "Content-Type": "application/json" 608 | }, 609 | data: { 610 | "body": {"name":"John Doe","baz":["qux","quix"]} 611 | } 612 | }) 613 | .then(response => response) 614 | .catch(error => { 615 | throw error; 616 | }); 617 | ``` 618 | 619 | ## Node (Axios) (GET) 620 | 621 | ```NodeAxios 622 | const axios = require('axios'); 623 | 624 | axios({ 625 | method: 'GET', 626 | url: 'http://example.com', 627 | params: { 628 | "baz": ["qux","quix"], 629 | "foo": "bar" 630 | } 631 | }) 632 | .then(response => response) 633 | .catch(error => { 634 | throw error; 635 | }); 636 | ``` 637 | 638 | ## Node (Fetch) (POST) 639 | 640 | ```NodeFetch 641 | const fetch = require('node-fetch'); 642 | 643 | const params = {}; 644 | const url = 'http://example.com' + (Object.keys(params).length ? '?' + new URLSearchParams(params).toString() : ''); 645 | 646 | const options = { 647 | method: 'POST', 648 | headers: { 649 | 'Content-Type': 'application/json' 650 | }, 651 | body: { 652 | "name": "John Doe", 653 | "baz": [ 654 | "qux", 655 | "quix" 656 | ] 657 | } 658 | }; 659 | 660 | const response = await fetch(url, options); 661 | const data = await response.json(); 662 | ``` 663 | 664 | ## Node (Fetch) (GET) 665 | 666 | ```NodeFetch 667 | const fetch = require('node-fetch'); 668 | 669 | const params = { 670 | "baz": [ 671 | "qux", 672 | "quix" 673 | ], 674 | "foo": "bar" 675 | }; 676 | const url = 'http://example.com' + (Object.keys(params).length ? '?' + new URLSearchParams(params).toString() : ''); 677 | 678 | const options = { 679 | method: 'GET' 680 | }; 681 | 682 | const response = await fetch(url, options); 683 | const data = await response.json(); 684 | ``` 685 | 686 | ## Objective-C (POST) 687 | 688 | ```ObjectiveC 689 | NSURL *url = [NSURL URLWithString:@"http://example.com"]; 690 | 691 | NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; 692 | [request setCachePolicy:NSURLRequestUseProtocolCachePolicy]; 693 | [request setTimeoutInterval:10.0]; 694 | [request setHTTPMethod:@"POST"]; 695 | 696 | NSDictionary *headers = @{ 697 | @"Content-Type": @"application/json" 698 | }; 699 | 700 | [headers enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { 701 | [request setValue:value forHTTPHeaderField:key]; 702 | }]; 703 | NSDictionary *httpBody = @{ 704 | @"name": @"John Doe", 705 | @"baz": @[@"qux", @"quix"] 706 | }; 707 | 708 | NSData *httpBodyData = [NSJSONSerialization dataWithJSONObject:httpBody options:0 error:nil]; 709 | [request setHTTPBody:httpBodyData]; 710 | 711 | NSURLSession *session = [NSURLSession sharedSession]; 712 | NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 713 | NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; 714 | }]; 715 | [task resume]; 716 | ``` 717 | 718 | ## Objective-C (GET) 719 | 720 | ```ObjectiveC 721 | NSURLComponents *components = [[NSURLComponents alloc] initWithString:@"http://example.com"]; 722 | NSMutableArray *queryItems = [NSMutableArray array]; 723 | [queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"baz" value:@"qux"]]; 724 | [queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"baz" value:@"quix"]]; 725 | [queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"foo" value:@"bar"]]; 726 | [components setQueryItems:queryItems]; 727 | NSURL *url = [components URL]; 728 | 729 | NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; 730 | [request setCachePolicy:NSURLRequestUseProtocolCachePolicy]; 731 | [request setTimeoutInterval:10.0]; 732 | [request setHTTPMethod:@"GET"]; 733 | 734 | 735 | NSURLSession *session = [NSURLSession sharedSession]; 736 | NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 737 | NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; 738 | }]; 739 | [task resume]; 740 | ``` 741 | 742 | ## PHP (POST) 743 | 744 | ```PHP 745 | [ 752 | 'method' => $method, 753 | 'header' => [ 754 | 'Content-Type: application/json', 755 | ], 756 | 'content' => json_encode([ 757 | 'name' => "John Doe", 758 | 'baz' => ["qux","quix"], 759 | ]), 760 | ], 761 | ]; 762 | 763 | $context = stream_context_create($options); 764 | $response = file_get_contents($url, false, $context); 765 | ``` 766 | 767 | ## PHP (GET) 768 | 769 | ```PHP 770 | ["qux","quix"], 776 | 'foo' => "bar", 777 | ]; 778 | $url .= '?' . http_build_query($query); 779 | 780 | $options = [ 781 | 'http' => [ 782 | 'method' => $method, 783 | ], 784 | ]; 785 | 786 | $context = stream_context_create($options); 787 | $response = file_get_contents($url, false, $context); 788 | ``` 789 | 790 | ## PHP (Guzzle) (POST) 791 | 792 | ```PHPGuzzle 793 | 'application/json', 803 | ]; 804 | 805 | $requestOptions['json'] = [ 806 | 'name' => "John Doe", 807 | 'baz' => ["qux","quix"], 808 | ]; 809 | 810 | try { 811 | $response = $client->request('POST', 'http://example.com', $requestOptions); 812 | } catch (\GuzzleHttp\Exception\RequestException $e) { 813 | $error = $e->getMessage(); 814 | } 815 | ``` 816 | 817 | ## PHP (Guzzle) (GET) 818 | 819 | ```PHPGuzzle 820 | 'qux', 830 | 'baz[]' => 'quix', 831 | 'foo' => 'bar', 832 | ]; 833 | 834 | try { 835 | $response = $client->request('GET', 'http://example.com', $requestOptions); 836 | } catch (\GuzzleHttp\Exception\RequestException $e) { 837 | $error = $e->getMessage(); 838 | } 839 | ``` 840 | 841 | ## PHP (Requests) (POST) 842 | 843 | ```PHPRequests 844 | 'application/json' 851 | ]; 852 | $query = []; 853 | $body = [ 854 | 'name' => 'John Doe', 855 | 'baz' => ["qux","quix"] 856 | ]; 857 | 858 | $response = Requests::request($url, $headers, $body, $method, $query); 859 | if ($response->status_code >= 400) { 860 | throw new Exception('Server responded with status code ' . $response->status_code); 861 | } 862 | ?> 863 | ``` 864 | 865 | ## PHP (Requests) (GET) 866 | 867 | ```PHPRequests 868 | ["qux","quix"], 876 | 'foo' => 'bar' 877 | ]; 878 | $body = []; 879 | 880 | $response = Requests::request($url, $headers, $body, $method, $query); 881 | if ($response->status_code >= 400) { 882 | throw new Exception('Server responded with status code ' . $response->status_code); 883 | } 884 | ?> 885 | ``` 886 | 887 | ## Python (POST) 888 | 889 | ```Python 890 | from urllib.parse import urlencode 891 | from urllib.request import Request, urlopen 892 | from urllib.error import HTTPError 893 | import json 894 | import ssl 895 | 896 | def call_api(): 897 | url = "http://example.com" 898 | request = Request(url) 899 | request.method = "POST" 900 | request.add_header("Content-Type", "application/json") 901 | data = { 902 | "name": "John Doe", 903 | "baz": [ 904 | "qux", 905 | "quix" 906 | ], 907 | } 908 | request.data = json.dumps(data).encode() 909 | ctx = ssl.create_default_context() 910 | try: 911 | response = urlopen(request, context=ctx) 912 | except HTTPError as e: 913 | response = e 914 | if response.code >= 400: 915 | raise 916 | return response 917 | 918 | ``` 919 | 920 | ## Python (GET) 921 | 922 | ```Python 923 | from urllib.parse import urlencode 924 | from urllib.request import Request, urlopen 925 | from urllib.error import HTTPError 926 | import json 927 | import ssl 928 | 929 | def call_api(): 930 | url = "http://example.com" 931 | query_params = { 932 | "baz": ["qux","quix"], 933 | "foo": "bar", 934 | } 935 | url = f"{url}?{urlencode(query_params)}" 936 | request = Request(url) 937 | request.method = "GET" 938 | ctx = ssl.create_default_context() 939 | try: 940 | response = urlopen(request, context=ctx) 941 | except HTTPError as e: 942 | response = e 943 | if response.code >= 400: 944 | raise 945 | return response 946 | 947 | ``` 948 | 949 | ## Python (Requests) (POST) 950 | 951 | ```PythonRequests 952 | import requests 953 | 954 | def call_api(): 955 | url = "http://example.com" 956 | params = None 957 | method = "POST" 958 | headers = { 959 | "Content-Type": "application/json", 960 | } 961 | data = { 962 | "name": "John Doe", 963 | "baz": ["qux","quix"], 964 | } 965 | response = requests.request(method, url, headers=headers, params=params, json=data if isinstance(data, dict) else data) 966 | 967 | ``` 968 | 969 | ## Python (Requests) (GET) 970 | 971 | ```PythonRequests 972 | import requests 973 | 974 | def call_api(): 975 | url = "http://example.com" 976 | params = { 977 | "baz": ["qux","quix"], 978 | "foo": "bar", 979 | } 980 | method = "GET" 981 | headers = None 982 | data = None 983 | response = requests.request(method, url, headers=headers, params=params, json=data if isinstance(data, dict) else data) 984 | 985 | ``` 986 | 987 | ## Ruby (POST) 988 | 989 | ```Ruby 990 | require 'net/http' 991 | require 'uri' 992 | require 'json' 993 | 994 | def send_request 995 | uri = URI.parse("http://example.com") 996 | http = Net::HTTP.new(uri.host, uri.port) 997 | http.use_ssl = uri.scheme == 'https' 998 | 999 | request = Net::HTTP::Post.new(uri.request_uri) 1000 | 1001 | request.initialize_http_header( 1002 | "Content-Type" => "application/json" 1003 | ) 1004 | 1005 | body = { 1006 | "name" => "John Doe", 1007 | "baz" => ["qux","quix"] 1008 | } 1009 | request.body = body.to_json 1010 | 1011 | begin 1012 | response = http.request(request) 1013 | case response 1014 | when Net::HTTPSuccess 1015 | response 1016 | else 1017 | raise "HTTP Error: #{response.code} - #{response.message}" 1018 | end 1019 | rescue StandardError => e 1020 | raise "Request failed: #{e.message}" 1021 | end 1022 | end 1023 | 1024 | send_request if __FILE__ == $PROGRAM_NAME 1025 | 1026 | ``` 1027 | 1028 | ## Ruby (GET) 1029 | 1030 | ```Ruby 1031 | require 'net/http' 1032 | require 'uri' 1033 | require 'json' 1034 | 1035 | def send_request 1036 | uri = URI.parse("http://example.com") 1037 | query_params = { 1038 | "baz" => qux,quix, 1039 | "foo" => bar 1040 | } 1041 | uri.query = URI.encode_www_form(query_params) 1042 | 1043 | http = Net::HTTP.new(uri.host, uri.port) 1044 | http.use_ssl = uri.scheme == 'https' 1045 | 1046 | request = Net::HTTP::Get.new(uri.request_uri) 1047 | 1048 | begin 1049 | response = http.request(request) 1050 | case response 1051 | when Net::HTTPSuccess 1052 | response 1053 | else 1054 | raise "HTTP Error: #{response.code} - #{response.message}" 1055 | end 1056 | rescue StandardError => e 1057 | raise "Request failed: #{e.message}" 1058 | end 1059 | end 1060 | 1061 | send_request if __FILE__ == $PROGRAM_NAME 1062 | 1063 | ``` 1064 | 1065 | ## Rust (POST) 1066 | 1067 | ```Rust 1068 | use reqwest::{Client, Method}; 1069 | use serde_json::Value; 1070 | 1071 | pub async fn make_request() -> Result { 1072 | let client = Client::new(); 1073 | let mut url = "http://example.com".parse()?; 1074 | let request = client.request(Method::POST, url) 1075 | .headers( 1076 | { 1077 | "Content-Type": "application/json" 1078 | } 1079 | .into()) 1080 | .json(&serde_json::json!( 1081 | { 1082 | "body": { 1083 | "name": "John Doe", 1084 | "baz": [ 1085 | "qux", 1086 | "quix" 1087 | ] 1088 | } 1089 | } 1090 | )) 1091 | .send() 1092 | .await?; 1093 | Ok(response) 1094 | } 1095 | ``` 1096 | 1097 | ## Rust (GET) 1098 | 1099 | ```Rust 1100 | use reqwest::{Client, Method}; 1101 | use serde_json::Value; 1102 | 1103 | pub async fn make_request() -> Result { 1104 | let client = Client::new(); 1105 | let mut url = "http://example.com".parse()?; 1106 | let query_params: Value = serde_json::json!( 1107 | { 1108 | "baz": [ 1109 | "qux", 1110 | "quix" 1111 | ], 1112 | "foo": "bar" 1113 | } 1114 | ); 1115 | if let Value::Object(params) = query_params { 1116 | let query_string = params.iter() 1117 | .flat_map(|(k, v)| match v { 1118 | Value::Array(arr) => arr.iter() 1119 | .map(|x| (k.clone(), x.to_string())) 1120 | .collect::>(), 1121 | _ => vec![(k.clone(), v.to_string())] 1122 | }) 1123 | .collect::>(); 1124 | url.query_pairs_mut().extend_pairs(query_string); 1125 | } 1126 | let request = client.request(Method::GET, url) 1127 | .send() 1128 | .await?; 1129 | Ok(response) 1130 | } 1131 | ``` 1132 | 1133 | ## Swift (POST) 1134 | 1135 | ```Swift 1136 | import Foundation 1137 | 1138 | var request = URLRequest(url: URL(string: "http://example.com")!,timeoutInterval: Double.infinity) 1139 | request.httpMethod = "POST" 1140 | request.addValue("application/json", forHTTPHeaderField: "Content-Type") 1141 | let parameters: [String: Any] = { 1142 | "name": "John Doe", 1143 | "baz": [ 1144 | "qux", 1145 | "quix" 1146 | ] 1147 | } 1148 | request.httpBody = try? JSONSerialization.data(withJSONObject: parameters) 1149 | request.addValue("application/json", forHTTPHeaderField: "Content-Type") 1150 | 1151 | let task = URLSession.shared.dataTask(with: request) { data, response, error in 1152 | if let error = error { 1153 | print("Error: \(error)") 1154 | return 1155 | } 1156 | let response = data 1157 | } 1158 | task.resume() 1159 | 1160 | ``` 1161 | 1162 | ## Swift (GET) 1163 | 1164 | ```Swift 1165 | import Foundation 1166 | 1167 | let components = URLComponents(string: "http://example.com")! 1168 | let queryItems: [URLQueryItem] = [ 1169 | URLQueryItem(name: "baz", value: "qux"), 1170 | URLQueryItem(name: "baz", value: "quix"), 1171 | URLQueryItem(name: "foo", value: "bar") 1172 | ] 1173 | components.queryItems = queryItems 1174 | 1175 | var request = URLRequest(url: components.url!,timeoutInterval: Double.infinity) 1176 | request.httpMethod = "GET" 1177 | 1178 | let task = URLSession.shared.dataTask(with: request) { data, response, error in 1179 | if let error = error { 1180 | print("Error: \(error)") 1181 | return 1182 | } 1183 | let response = data 1184 | } 1185 | task.resume() 1186 | 1187 | ``` 1188 | 1189 | ## Wget (POST) 1190 | 1191 | ```Wget 1192 | wget --post-data '{"name":"John Doe","baz":["qux","quix"]}' \ 1193 | --header 'Content-Type: application/json' \ 1194 | 'http://example.com' 1195 | ``` 1196 | 1197 | ## Wget (GET) 1198 | 1199 | ```Wget 1200 | wget \ 1201 | 'http://example.com?baz=qux&baz=quix&foo=bar' 1202 | ``` 1203 | 1204 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "requestcodegen", 3 | "version": "0.0.3", 4 | "description": "A library to generate HTTP client example code in different programming languages.", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/krasun/requestcodegen.git" 8 | }, 9 | "author": "Dmytro Krasun", 10 | "license": "MIT", 11 | "bugs": { 12 | "url": "https://github.com/krasun/requestcodegen/issues" 13 | }, 14 | "main": "dist/generator.js", 15 | "types": "dist/@types/generator.d.ts", 16 | "devDependencies": { 17 | "@jest/globals": "^29.7.0", 18 | "@types/jest": "^29.5.14", 19 | "@types/node": "^17.0.40", 20 | "jest": "^29.7.0", 21 | "openai": "^4.24.1", 22 | "ts-jest": "^29.1.1", 23 | "ts-node": "^10.9.2", 24 | "typescript": "^4.7.3" 25 | }, 26 | "scripts": { 27 | "test": "jest", 28 | "generate": "ts-node ./src/scripts/generate.ts", 29 | "examples": "ts-node ./src/scripts/examples.ts ./examples.md", 30 | "build": "./node_modules/typescript/bin/tsc", 31 | "prepare": "npm run build" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/code.ts: -------------------------------------------------------------------------------- 1 | export function cleanUpMarkdownCode(code: string): string { 2 | if (!code.startsWith("```")) { 3 | return code; 4 | } 5 | 6 | const codeBlockRegex = /```[a-zA-Z]+\n([\s\S]*?)```/g; 7 | 8 | let match = codeBlockRegex.exec(code); 9 | let cleanedCode = ""; 10 | while (match != null) { 11 | cleanedCode += match[1] + "\n"; 12 | match = codeBlockRegex.exec(code); 13 | } 14 | 15 | return cleanedCode.trim(); 16 | } 17 | 18 | export function generateComparableCode(s: string) { 19 | // remove non-printable and whitespace characters 20 | return s.replace(/[\s\x00-\x1F\x7F-\x9F]/g, ""); 21 | } 22 | -------------------------------------------------------------------------------- /src/generator.ts: -------------------------------------------------------------------------------- 1 | import { generateClojureCode } from "./generators/clojure"; 2 | import { generateCSharpCode } from "./generators/csharp"; 3 | import { generateCurlCode } from "./generators/curl"; 4 | import { generateDartCode } from "./generators/dart"; 5 | import { generateElixirCode } from "./generators/elixir"; 6 | import { generateGoCode } from "./generators/go"; 7 | import { generateJavaCode } from "./generators/java"; 8 | import { generateJavaScriptCode } from "./generators/javascript"; 9 | import { generateKotlinCode } from "./generators/kotlin"; 10 | import { generateNodeAxiosCode } from "./generators/node-axios"; 11 | import { generateNodeFetchCode } from "./generators/node-fetch"; 12 | import { generateNodeHTTPCode } from "./generators/node-http"; 13 | import { generateObjectiveCCode } from "./generators/objective-c"; 14 | import { generatePHPCode } from "./generators/php"; 15 | import { generatePHPGuzzleCode } from "./generators/php-guzzle"; 16 | import { generatePHPRequestsCode } from "./generators/php-requests"; 17 | import { generatePythonCode } from "./generators/python"; 18 | import { generatePythonRequestsCode } from "./generators/python-requests"; 19 | import { generateRubyCode } from "./generators/ruby"; 20 | import { generateRustCode } from "./generators/rust"; 21 | import { generateSwiftCode } from "./generators/swift"; 22 | import { generateWgetCode } from "./generators/wget"; 23 | import { JsonBody, RequestOptions } from "./request"; 24 | import { CodeTarget } from "./target"; 25 | 26 | export * from "./target"; 27 | export * from "./request"; 28 | 29 | export function generateCode( 30 | request: RequestOptions, 31 | target: CodeTarget 32 | ): string { 33 | if (request.body instanceof JsonBody) { 34 | if (request.headers) { 35 | const contentType = 36 | request.headers["Content-Type"] || 37 | request.headers["content-type"]; 38 | if (!contentType || !contentType.includes("application/json")) { 39 | request.headers["Content-Type"] = "application/json"; 40 | } 41 | } 42 | } 43 | 44 | switch (target) { 45 | case CodeTarget.Clojure: 46 | return generateClojureCode(request); 47 | case CodeTarget.CSharp: 48 | return generateCSharpCode(request); 49 | case CodeTarget.Curl: 50 | return generateCurlCode(request); 51 | case CodeTarget.Dart: 52 | return generateDartCode(request); 53 | case CodeTarget.Elixir: 54 | return generateElixirCode(request); 55 | case CodeTarget.Go: 56 | return generateGoCode(request); 57 | case CodeTarget.Java: 58 | return generateJavaCode(request); 59 | case CodeTarget.JavaScript: 60 | return generateJavaScriptCode(request); 61 | case CodeTarget.Kotlin: 62 | return generateKotlinCode(request); 63 | case CodeTarget.NodeHTTP: 64 | return generateNodeHTTPCode(request); 65 | case CodeTarget.NodeAxios: 66 | return generateNodeAxiosCode(request); 67 | case CodeTarget.NodeFetch: 68 | return generateNodeFetchCode(request); 69 | case CodeTarget.ObjectiveC: 70 | return generateObjectiveCCode(request); 71 | case CodeTarget.PHP: 72 | return generatePHPCode(request); 73 | case CodeTarget.PHPGuzzle: 74 | return generatePHPGuzzleCode(request); 75 | case CodeTarget.PHPRequests: 76 | return generatePHPRequestsCode(request); 77 | case CodeTarget.Python: 78 | return generatePythonCode(request); 79 | case CodeTarget.PythonRequests: 80 | return generatePythonRequestsCode(request); 81 | case CodeTarget.Ruby: 82 | return generateRubyCode(request); 83 | case CodeTarget.Rust: 84 | return generateRustCode(request); 85 | case CodeTarget.Swift: 86 | return generateSwiftCode(request); 87 | case CodeTarget.Wget: 88 | return generateWgetCode(request); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/generators/clojure.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateClojureCode } from "./clojure"; 3 | 4 | describe('generateClojureCode', () => { 5 | test('should generate code with only url', () => { 6 | const options = { url: 'http://example.com' }; 7 | const result = generateClojureCode(options); 8 | expect(result).toContain(':url "http://example.com"'); 9 | }); 10 | 11 | test('should generate code with url and query', () => { 12 | const options = { url: 'http://example.com', query: { foo: 'bar' } }; 13 | const result = generateClojureCode(options); 14 | expect(result).toContain(':url "http://example.com"'); 15 | expect(result).toContain(':query-params {"foo" "bar"}'); 16 | }); 17 | 18 | test('should generate code with url and method', () => { 19 | const options = { url: 'http://example.com', method: 'POST' }; 20 | const result = generateClojureCode(options); 21 | expect(result).toContain(':url "http://example.com"'); 22 | expect(result).toContain(':method :post'); 23 | }); 24 | 25 | test('should generate code with url and headers', () => { 26 | const options = { url: 'http://example.com', headers: { 'Content-Type': 'application/json' } }; 27 | const result = generateClojureCode(options); 28 | expect(result).toContain(':url "http://example.com"'); 29 | expect(result).toContain(':headers {"Content-Type" "application/json"}'); 30 | }); 31 | 32 | test('should generate code with url and body', () => { 33 | const options = { url: 'http://example.com', body: 'Hello, World!' }; 34 | const result = generateClojureCode(options); 35 | expect(result).toContain(':url "http://example.com"'); 36 | expect(result).toContain(':body "Hello, World!"'); 37 | }); 38 | }); -------------------------------------------------------------------------------- /src/generators/clojure.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptions, JsonBody } from "../request"; 2 | 3 | function formatClojureMap(obj: any): string { 4 | if (typeof obj !== 'object' || obj === null) { 5 | return `"${obj}"`; 6 | } 7 | 8 | const entries = Object.entries(obj).map(([k, v]) => { 9 | if (Array.isArray(v)) { 10 | const items = v.map(item => formatClojureMap(item)).join(" "); 11 | return `"${k}" [${items}]`; 12 | } 13 | if (typeof v === 'object' && v !== null) { 14 | return `"${k}" ${formatClojureMap(v)}`; 15 | } 16 | return `"${k}" "${v}"`; 17 | }); 18 | 19 | return `{${entries.join("\n ")}}`; 20 | } 21 | 22 | export function generateClojureCode(options: RequestOptions): string { 23 | let code = `(ns my.namespace 24 | (:require [clj-http.client :as client])) 25 | 26 | (defn make-request [] 27 | (client/request 28 | {`; 29 | 30 | code += `\n :url "${options.url}"`; 31 | 32 | if (options.query) { 33 | code += `\n :query-params ${formatClojureMap(options.query)}`; 34 | } 35 | 36 | if (options.method) { 37 | code += `\n :method :${options.method.toLowerCase()}`; 38 | } 39 | 40 | if (options.headers) { 41 | code += `\n :headers ${formatClojureMap(options.headers)}`; 42 | } 43 | 44 | if (options.body) { 45 | const body = options.body instanceof JsonBody ? options.body.body : options.body; 46 | code += `\n :body ${formatClojureMap(body)}`; 47 | } 48 | 49 | code += `}))\n`; 50 | 51 | return code; 52 | } 53 | -------------------------------------------------------------------------------- /src/generators/csharp.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateCSharpCode } from "./csharp"; 3 | 4 | describe('generateCSharpCode', () => { 5 | test('should generate correct code with GET method and no headers, body or query', () => { 6 | const options = { 7 | method: 'GET', 8 | url: 'https://example.com' 9 | }; 10 | const result = generateCSharpCode(options); 11 | expect(result).toContain('Method = new HttpMethod("GET")'); 12 | expect(result).toContain('RequestUri = new Uri("https://example.com")'); 13 | }); 14 | 15 | test('should generate correct code with POST method and headers', () => { 16 | const options = { 17 | method: 'POST', 18 | url: 'https://example.com', 19 | headers: { 20 | 'Content-Type': 'application/json' 21 | } 22 | }; 23 | const result = generateCSharpCode(options); 24 | expect(result).toContain('Method = new HttpMethod("POST")'); 25 | expect(result).toContain('request.Headers.Add("Content-Type", "application/json");'); 26 | }); 27 | 28 | test('should generate correct code with body', () => { 29 | const options = { 30 | method: 'POST', 31 | url: 'https://example.com', 32 | body: '{"key":"value"}' 33 | }; 34 | const result = generateCSharpCode(options); 35 | expect(result).toContain('request.Content = new StringContent("{\"key\":\"value\"}");'); 36 | }); 37 | 38 | test('should generate correct code with query parameters', () => { 39 | const options = { 40 | method: 'GET', 41 | url: 'https://example.com', 42 | query: { 43 | 'key': 'value' 44 | } 45 | }; 46 | const result = generateCSharpCode(options); 47 | expect(result).toContain('query["key"] = "value";'); 48 | }); 49 | 50 | test('should generate correct code with array query parameters', () => { 51 | const options = { 52 | method: 'GET', 53 | url: 'https://example.com', 54 | query: { 55 | 'key': ['value1', 'value2'] 56 | } 57 | }; 58 | const result = generateCSharpCode(options); 59 | expect(result).toContain('query["key"] = "value1";'); 60 | expect(result).toContain('query["key"] = "value2";'); 61 | }); 62 | }); -------------------------------------------------------------------------------- /src/generators/csharp.ts: -------------------------------------------------------------------------------- 1 | import { JsonBody, RequestOptions } from "../request"; 2 | 3 | export function generateCSharpCode(options: RequestOptions): string { 4 | // Remove content-type from headers if it's JSON since it will be set by StringContent 5 | const headers = { ...options.headers }; 6 | const isJsonContent = 7 | headers && 8 | Object.entries(headers).some( 9 | ([key, value]) => 10 | key.toLowerCase() === "content-type" && 11 | value.toLowerCase().includes("json") 12 | ); 13 | 14 | // Helper function to convert JSON to C# object initialization syntax 15 | function toCSharpObject(obj: any, indent: number = 3): string { 16 | if (obj === null) return "null"; 17 | if (typeof obj === "string") return `"${obj}"`; 18 | if (typeof obj === "number" || typeof obj === "boolean") 19 | return obj.toString(); 20 | if (Array.isArray(obj)) { 21 | if (obj.length === 0) return "new object[] {}"; 22 | const items = obj 23 | .map((item) => toCSharpObject(item, indent + 1)) 24 | .join(",\n" + " ".repeat(indent * 4)); 25 | return `new object[] {\n${" ".repeat( 26 | indent * 4 27 | )}${items}\n${" ".repeat((indent - 1) * 4)}}`; 28 | } 29 | if (obj instanceof JsonBody) { 30 | const entries = Object.entries(obj.body); 31 | if (entries.length === 0) return "new {}"; 32 | const props = entries 33 | .map( 34 | ([key, value]) => 35 | `${key} = ${toCSharpObject(value, indent + 1)}` 36 | ) 37 | .join(",\n" + " ".repeat(indent * 4)); 38 | return `new {\n${" ".repeat(indent * 4)}${props}\n${" ".repeat( 39 | (indent - 1) * 4 40 | )}}`; 41 | } 42 | return "null"; 43 | } 44 | 45 | let code = `using System; 46 | using System.Net.Http; 47 | using System.Threading.Tasks; 48 | using System.Text.Json; 49 | 50 | public class Program { 51 | public static async Task Main(string[] args) { 52 | using var client = new HttpClient(); 53 | ${ 54 | isJsonContent && options.body 55 | ? `var requestData = ${toCSharpObject( 56 | options.body 57 | )};\n\n ` 58 | : "" 59 | }var request = new HttpRequestMessage { 60 | Method = new HttpMethod("${options.method || "GET"}"), 61 | RequestUri = new Uri("${options.url}") 62 | }; 63 | ${Object.entries(headers || {}) 64 | .map( 65 | ([key, value]) => 66 | `request.Headers.Add("${key}", "${value}");\n ` 67 | ) 68 | .join("")} 69 | ${ 70 | options.body 71 | ? isJsonContent 72 | ? `var jsonOptions = new JsonSerializerOptions { 73 | }; 74 | request.Content = new StringContent( 75 | JsonSerializer.Serialize(requestData, jsonOptions), 76 | System.Text.Encoding.UTF8, 77 | "application/json" 78 | );` 79 | : `request.Content = new StringContent("${options.body}");` 80 | : "" 81 | } 82 | ${ 83 | options.query 84 | ? `var query = System.Web.HttpUtility.ParseQueryString(string.Empty); 85 | ${Object.entries(options.query) 86 | .map(([key, value]) => { 87 | if (Array.isArray(value)) { 88 | return value 89 | .map((v) => `query["${key}"] = "${v}";\n `) 90 | .join(""); 91 | } else { 92 | return `query["${key}"] = "${value}";\n `; 93 | } 94 | }) 95 | .join( 96 | "" 97 | )}request.RequestUri = new Uri(request.RequestUri + "?" + query);` 98 | : "" 99 | } 100 | try { 101 | using var response = await client.SendAsync(request); 102 | response.EnsureSuccessStatusCode(); 103 | } catch (Exception ex) { 104 | Console.WriteLine(ex.ToString()); 105 | } 106 | } 107 | }`; 108 | return code; 109 | } 110 | -------------------------------------------------------------------------------- /src/generators/curl.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateCurlCode } from "./curl"; 3 | 4 | describe('generateCurlCode', () => { 5 | test('should generate curl code with GET method and no query, headers or body', () => { 6 | const options = { 7 | method: 'GET', 8 | url: 'https://example.com', 9 | }; 10 | expect(generateCurlCode(options)).toBe("curl -X GET 'https://example.com'"); 11 | }); 12 | 13 | test('should generate curl code with POST method and query parameters', () => { 14 | const options = { 15 | method: 'POST', 16 | url: 'https://example.com', 17 | query: { 18 | param1: 'value1', 19 | param2: 'value2', 20 | }, 21 | }; 22 | expect(generateCurlCode(options)).toBe("curl -X POST 'https://example.com?param1=value1¶m2=value2'"); 23 | }); 24 | 25 | test('should generate curl code with PUT method, headers and body', () => { 26 | const options = { 27 | method: 'PUT', 28 | url: 'https://example.com', 29 | headers: { 30 | 'Content-Type': 'application/json', 31 | }, 32 | body: '{"key":"value"}', 33 | }; 34 | expect(generateCurlCode(options)).toBe("curl -X PUT 'https://example.com' -H 'Content-Type: application/json' -d '{\"key\":\"value\"}'"); 35 | }); 36 | 37 | test('should generate curl code with DELETE method and array query parameters', () => { 38 | const options = { 39 | method: 'DELETE', 40 | url: 'https://example.com', 41 | query: { 42 | param: ['value1', 'value2'], 43 | }, 44 | }; 45 | expect(generateCurlCode(options)).toBe("curl -X DELETE 'https://example.com?param=value1,value2'"); 46 | }); 47 | 48 | test('should generate curl code with PATCH method, headers, query parameters and body', () => { 49 | const options = { 50 | method: 'PATCH', 51 | url: 'https://example.com', 52 | query: { 53 | param: 'value', 54 | }, 55 | headers: { 56 | 'Content-Type': 'application/json', 57 | }, 58 | body: '{"key":"value"}', 59 | }; 60 | expect(generateCurlCode(options)).toBe("curl -X PATCH 'https://example.com?param=value' -H 'Content-Type: application/json' -d '{\"key\":\"value\"}'"); 61 | }); 62 | }); -------------------------------------------------------------------------------- /src/generators/curl.ts: -------------------------------------------------------------------------------- 1 | import { JsonBody, RequestOptions } from "../request"; 2 | 3 | export function generateCurlCode(options: RequestOptions): string { 4 | let curlCode = `curl -X ${options.method || "GET"} '${options.url}`; 5 | 6 | if (options.query) { 7 | const queryString = Object.entries(options.query) 8 | .map( 9 | ([key, value]) => 10 | `${key}=${Array.isArray(value) ? value.join(",") : value}` 11 | ) 12 | .join("&"); 13 | curlCode += `?${queryString}`; 14 | } 15 | 16 | curlCode += `'`; 17 | 18 | if (options.headers) { 19 | const headersString = Object.entries(options.headers) 20 | .map(([key, value]) => `-H '${key}: ${value}'`) 21 | .join(" "); 22 | curlCode += ` ${headersString}`; 23 | } 24 | 25 | if (options.body) { 26 | if (options.body instanceof JsonBody) { 27 | curlCode += ` -d '${JSON.stringify(options.body.body)}'`; 28 | } else { 29 | curlCode += ` -d '${options.body}'`; 30 | } 31 | } 32 | 33 | return curlCode; 34 | } 35 | -------------------------------------------------------------------------------- /src/generators/dart.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateDartCode } from "./dart"; 3 | import { JsonBody } from "../request"; 4 | 5 | describe("generateDartCode", () => { 6 | test("should generate code with GET method and no headers", () => { 7 | const options = { 8 | url: "https://example.com", 9 | method: "GET", 10 | }; 11 | const result = generateDartCode(options); 12 | expect(result).toContain("final response = await http.get("); 13 | expect(result).toContain("url"); 14 | }); 15 | 16 | test("should generate code with POST method and headers", () => { 17 | const options = { 18 | url: "https://example.com", 19 | method: "POST", 20 | headers: { 21 | "Content-Type": "application/json", 22 | }, 23 | }; 24 | const result = generateDartCode(options); 25 | expect(result).toContain("final response = await http.post("); 26 | expect(result).toContain('"Content-Type": "application/json"'); 27 | }); 28 | 29 | test("should generate code with PUT method, headers and JSON body", () => { 30 | const options = { 31 | url: "https://example.com", 32 | method: "PUT", 33 | headers: { 34 | "Content-Type": "application/json", 35 | }, 36 | body: new JsonBody({ 37 | key: "value", 38 | nested: { 39 | data: "test" 40 | } 41 | }), 42 | }; 43 | const result = generateDartCode(options); 44 | expect(result).toContain("final response = await http.put("); 45 | expect(result).toContain('"Content-Type": "application/json"'); 46 | expect(result).toContain("final options = {"); 47 | expect(result).toContain('"key": "value"'); 48 | expect(result).toContain("body: jsonEncode(options)"); 49 | }); 50 | 51 | test("should generate code with query parameters", () => { 52 | const options = { 53 | url: "https://example.com", 54 | method: "GET", 55 | query: { 56 | key: "value", 57 | filter: "active" 58 | }, 59 | }; 60 | const result = generateDartCode(options); 61 | expect(result).toContain("final queryParameters = {"); 62 | expect(result).toContain('"key": "value"'); 63 | expect(result).toContain('"filter": "active"'); 64 | expect(result).toContain("final urlWithQuery = url.replace(queryParameters: queryParameters)"); 65 | }); 66 | 67 | test("should handle non-200 status code with proper error message", () => { 68 | const options = { 69 | url: "https://example.com", 70 | method: "GET", 71 | }; 72 | const result = generateDartCode(options); 73 | expect(result).toContain("throw Exception('Request failed with status: ${response.statusCode}')"); 74 | }); 75 | 76 | test("should handle raw string body", () => { 77 | const options = { 78 | url: "https://example.com", 79 | method: "POST", 80 | body: "raw string data", 81 | }; 82 | const result = generateDartCode(options); 83 | expect(result).toContain("body: 'raw string data'"); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /src/generators/dart.ts: -------------------------------------------------------------------------------- 1 | import { JsonBody, RequestOptions } from "../request"; 2 | 3 | export function generateDartCode(options: RequestOptions): string { 4 | let code = `import 'dart:convert'; 5 | import 'package:http/http.dart' as http; 6 | 7 | Future request() async { 8 | final url = Uri.parse('${options.url}');`; 9 | 10 | if (options.query) { 11 | code += `\n final queryParameters = ${JSON.stringify( 12 | options.query, 13 | null, 14 | 4 15 | ) 16 | .split("\n") 17 | .map((line, index) => (index === 0 ? line : " " + line)) 18 | .join("\n")};`; 19 | code += `\n final urlWithQuery = url.replace(queryParameters: queryParameters);`; 20 | } 21 | 22 | if (options.method === "POST" || options.method === "PUT") { 23 | if (options.body && options.body instanceof JsonBody) { 24 | code += `\n`; 25 | code += `\n final options = ${JSON.stringify( 26 | options.body.body, 27 | null, 28 | 4 29 | ) 30 | .split("\n") 31 | .map((line, index) => (index === 0 ? line : " " + line)) 32 | .join("\n")};`; 33 | } 34 | 35 | code += `\n\n final response = await http.${options.method.toLowerCase()}(`; 36 | code += `\n ${options.query ? "urlWithQuery" : "url"}`; 37 | 38 | if (options.headers) { 39 | code += `,\n headers: ${JSON.stringify( 40 | options.headers, 41 | null, 42 | 4 43 | ) 44 | .split("\n") 45 | .map((line, index) => (index === 0 ? line : " " + line)) 46 | .join("\n")}`; 47 | } 48 | 49 | if (options.body) { 50 | if (options.body instanceof JsonBody) { 51 | code += `,\n body: jsonEncode(options)`; 52 | } else { 53 | code += `,\n body: '${options.body}'`; 54 | } 55 | } 56 | 57 | code += `\n );`; 58 | } else { 59 | code += `\n\n final response = await http.get(`; 60 | code += `\n ${options.query ? "urlWithQuery" : "url"}`; 61 | 62 | if (options.headers) { 63 | code += `,\n headers: ${JSON.stringify( 64 | options.headers, 65 | null, 66 | 4 67 | ) 68 | .split("\n") 69 | .map((line, index) => (index === 0 ? line : " " + line)) 70 | .join("\n")}`; 71 | } 72 | 73 | code += `\n );`; 74 | } 75 | 76 | code += `\n\n if (response.statusCode != 200) { 77 | throw Exception('Request failed with status: \${response.statusCode}'); 78 | } 79 | 80 | // process response 81 | }`; 82 | 83 | return code; 84 | } 85 | -------------------------------------------------------------------------------- /src/generators/elixir.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateElixirCode } from "./elixir"; 3 | 4 | describe("generateElixirCode", () => { 5 | test("should return correct code for GET request with query params", () => { 6 | const options = { 7 | method: "GET", 8 | url: "http://example.com", 9 | headers: { "Content-Type": "application/json" }, 10 | query: { key: "value", array: ["item1", "item2"] }, 11 | }; 12 | const result = generateElixirCode(options); 13 | expect(result).toContain("use HTTPoison.Base"); 14 | expect(result).toContain("get!(url, headers, params: params)"); 15 | expect(result).toContain('"key": "value"'); 16 | expect(result).toContain('"array": ["item1","item2"]'); 17 | }); 18 | 19 | test("should return correct code for POST request with JSON body", () => { 20 | const options = { 21 | method: "POST", 22 | url: "http://example.com", 23 | headers: { "Content-Type": "application/json" }, 24 | body: JSON.stringify({ 25 | key: "value", 26 | nested: { 27 | array: [1, 2, 3] 28 | } 29 | }), 30 | }; 31 | const result = generateElixirCode(options); 32 | expect(result).toContain("post!(url, body, headers, params: params)"); 33 | expect(result).toContain('{"key":"value","nested":{"array":[1,2,3]}}'); 34 | }); 35 | 36 | test("should handle empty headers and query params", () => { 37 | const options = { 38 | method: "GET", 39 | url: "http://example.com" 40 | }; 41 | const result = generateElixirCode(options); 42 | expect(result).toContain("headers = %{}"); 43 | expect(result).toContain("params = %{}"); 44 | expect(result).toContain("body = nil"); 45 | }); 46 | 47 | test("should handle string body", () => { 48 | const options = { 49 | method: "POST", 50 | url: "http://example.com", 51 | body: "plain text body" 52 | }; 53 | const result = generateElixirCode(options); 54 | expect(result).toContain('body = "plain text body"'); 55 | }); 56 | 57 | test("should support all HTTP methods", () => { 58 | const methods = ["GET", "POST", "PUT", "DELETE", "PATCH"]; 59 | methods.forEach(method => { 60 | const options = { 61 | method, 62 | url: "http://example.com" 63 | }; 64 | const result = generateElixirCode(options); 65 | expect(result).not.toContain('case :${method.toLowerCase()} do'); 66 | expect(result).toContain(`${method.toLowerCase()}!(url,`); 67 | }); 68 | }); 69 | 70 | test("should return error for invalid method", () => { 71 | const options = { 72 | method: "INVALID", 73 | url: "http://example.com" 74 | }; 75 | const result = generateElixirCode(options); 76 | expect(result).toContain('response = HTTPoison.invalid!(url, headers, params: params)'); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /src/generators/elixir.ts: -------------------------------------------------------------------------------- 1 | import { JsonBody, RequestOptions } from "../request"; 2 | 3 | export function generateElixirCode(options: RequestOptions): string { 4 | function formatMap(obj: any): string { 5 | if (!obj || Object.keys(obj).length === 0) return "%{}"; 6 | 7 | const entries = Object.entries(obj).map(([key, value]) => { 8 | if (Array.isArray(value)) { 9 | return ` "${key}": ${JSON.stringify(value)}`; 10 | } 11 | if (typeof value === 'object' && value !== null) { 12 | return ` "${key}": ${JSON.stringify(value)}`; 13 | } 14 | return ` "${key}": "${value}"`; 15 | }); 16 | 17 | return "%{\n" + entries.join(",\n") + "\n }"; 18 | } 19 | 20 | function formatBody(body: any): string { 21 | if (!body) return "nil"; 22 | 23 | if (body instanceof JsonBody) { 24 | return formatMap(body.body); 25 | } 26 | 27 | return `"${body}"`; 28 | } 29 | 30 | const method = (options.method || "GET").toLowerCase(); 31 | const headers = formatMap(options.headers || {}); 32 | const params = formatMap(options.query || {}); 33 | const body = formatBody(options.body); 34 | 35 | const code = `defmodule Example do 36 | use HTTPoison.Base 37 | 38 | def request do 39 | url = "${options.url}" 40 | headers = ${headers} 41 | params = ${params} 42 | body = ${body} 43 | 44 | response = HTTPoison.${method}!(url${body !== "nil" ? ", body" : ""}, headers, params: params) 45 | end 46 | end`; 47 | 48 | return code; 49 | } 50 | -------------------------------------------------------------------------------- /src/generators/go.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateGoCode } from "./go"; 3 | import { JsonBody } from "../request"; 4 | 5 | describe('generateGoCode', () => { 6 | test('should generate correct code with GET method', () => { 7 | const options = { 8 | url: 'http://example.com', 9 | method: 'GET' 10 | }; 11 | const result = generateGoCode(options); 12 | expect(result).toContain('method := "GET"'); 13 | expect(result).toContain('url := "http://example.com"'); 14 | }); 15 | 16 | test('should generate correct code with POST method and body', () => { 17 | const options = { 18 | url: 'http://example.com', 19 | method: 'POST', 20 | body: '{"key":"value"}' 21 | }; 22 | const result = generateGoCode(options); 23 | expect(result).toContain('method := "POST"'); 24 | expect(result).toContain('jsonBody := `{"key":"value"}`'); 25 | }); 26 | 27 | test('should generate correct code with complex JSON body', () => { 28 | const options = { 29 | url: 'http://example.com', 30 | method: 'POST', 31 | body: new JsonBody({ 32 | key1: 'value1', 33 | key2: { 34 | nested: 'value2' 35 | }, 36 | array: [1, 2, 3] 37 | }) 38 | }; 39 | const result = generateGoCode(options); 40 | expect(result).toContain('jsonBody := `{'); 41 | expect(result).toContain(' "key1": "value1"'); 42 | expect(result).toContain(' "key2": {'); 43 | expect(result).toContain(' "nested": "value2"'); 44 | expect(result).toContain(' }'); 45 | expect(result).toContain(' "array": ['); 46 | expect(result).toContain(' 1,'); 47 | expect(result).toContain(' 2,'); 48 | expect(result).toContain(' 3'); 49 | expect(result).toContain(' ]'); 50 | expect(result).toContain('}`'); 51 | }); 52 | 53 | test('should generate correct code with headers', () => { 54 | const options = { 55 | url: 'http://example.com', 56 | method: 'GET', 57 | headers: { 58 | 'Content-Type': 'application/json' 59 | } 60 | }; 61 | const result = generateGoCode(options); 62 | expect(result).toContain('req.Header.Add("Content-Type", "application/json")'); 63 | }); 64 | 65 | test('should generate correct code with query parameters', () => { 66 | const options = { 67 | url: 'http://example.com', 68 | method: 'GET', 69 | query: { 70 | 'key': 'value' 71 | } 72 | }; 73 | const result = generateGoCode(options); 74 | expect(result).toContain('params.Add("key", "value")'); 75 | }); 76 | 77 | test('should generate correct code with array query parameters', () => { 78 | const options = { 79 | url: 'http://example.com', 80 | method: 'GET', 81 | query: { 82 | 'key': ['value1', 'value2'] 83 | } 84 | }; 85 | const result = generateGoCode(options); 86 | expect(result).toContain('params.Add("key", "value1")'); 87 | expect(result).toContain('params.Add("key", "value2")'); 88 | }); 89 | 90 | test('should generate correct code with complex query parameters', () => { 91 | const options = { 92 | url: 'http://example.com', 93 | method: 'GET', 94 | query: { 95 | 'filter': 'active', 96 | 'sort': ['name', 'date'], 97 | 'page': '1', 98 | 'limit': '10', 99 | 'include': ['details', 'metadata'] 100 | } 101 | }; 102 | const result = generateGoCode(options); 103 | expect(result).toContain('params.Add("filter", "active")'); 104 | expect(result).toContain('params.Add("sort", "name")'); 105 | expect(result).toContain('params.Add("sort", "date")'); 106 | expect(result).toContain('params.Add("page", "1")'); 107 | expect(result).toContain('params.Add("limit", "10")'); 108 | expect(result).toContain('params.Add("include", "details")'); 109 | expect(result).toContain('params.Add("include", "metadata")'); 110 | }); 111 | }); -------------------------------------------------------------------------------- /src/generators/go.ts: -------------------------------------------------------------------------------- 1 | import { JsonBody, RequestOptions } from "../request"; 2 | 3 | export function generateGoCode(options: RequestOptions): string { 4 | // Helper function to format query parameters 5 | function formatQueryParams(query: any): string { 6 | if (!query) return ""; 7 | const entries = Object.entries(query); 8 | if (entries.length === 0) return ""; 9 | 10 | const params = entries 11 | .map(([key, value]) => { 12 | if (Array.isArray(value)) { 13 | return value 14 | .map((v) => ` params.Add("${key}", "${v}")`) 15 | .join("\n"); 16 | } 17 | return ` params.Add("${key}", "${value}")`; 18 | }) 19 | .join("\n"); 20 | 21 | return ` 22 | params := url.Values{}\n${params} 23 | req.URL.RawQuery = params.Encode()`; 24 | } 25 | 26 | // Helper function to format headers 27 | function formatHeaders(headers: any): string { 28 | if (!headers) return ""; 29 | const entries = Object.entries(headers); 30 | if (entries.length === 0) return ""; 31 | 32 | return entries 33 | .map( 34 | ([key, value]) => ` req.Header.Add("${key}", "${value}")` 35 | ) 36 | .join("\n"); 37 | } 38 | 39 | function formatBody(body: any): string { 40 | if (body instanceof JsonBody) { 41 | return JSON.stringify(body.body, null, 4); 42 | } 43 | 44 | return body; 45 | } 46 | 47 | const code = `package main 48 | 49 | import ( 50 | "bytes" 51 | "fmt" 52 | "io" 53 | "net/http" 54 | "net/url" 55 | ) 56 | 57 | func main() { 58 | client := &http.Client{} 59 | 60 | url := "${options.url}" 61 | method := "${options.method || "GET"}" 62 | 63 | var req *http.Request 64 | var err error 65 | ${ 66 | options.body 67 | ? ` 68 | jsonBody := \`${formatBody(options.body)}\` 69 | req, err = http.NewRequest(method, url, bytes.NewBufferString(jsonBody))` 70 | : ` 71 | req, err = http.NewRequest(method, url, nil)` 72 | } 73 | if err != nil { 74 | fmt.Println(err) 75 | return 76 | } 77 | ${options.headers ? `\n${formatHeaders(options.headers)}` : ""}${ 78 | options.query ? formatQueryParams(options.query) : "" 79 | } 80 | 81 | resp, err := client.Do(req) 82 | if err != nil { 83 | fmt.Println(err) 84 | return 85 | } 86 | defer resp.Body.Close() 87 | }`; 88 | 89 | return code; 90 | } 91 | -------------------------------------------------------------------------------- /src/generators/java.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateJavaCode } from "./java"; 3 | import { JsonBody } from "../request"; 4 | 5 | describe('generateJavaCode', () => { 6 | test('should return correct code when only url is provided', () => { 7 | const options = { url: 'http://example.com' }; 8 | const result = generateJavaCode(options); 9 | expect(result).toContain('StringBuilder urlBuilder = new StringBuilder("http://example.com")'); 10 | expect(result).toContain('conn.setRequestMethod("GET")'); 11 | }); 12 | 13 | test('should return correct code when method is provided', () => { 14 | const options = { url: 'http://example.com', method: 'POST' }; 15 | const result = generateJavaCode(options); 16 | expect(result).toContain('conn.setRequestMethod("POST")'); 17 | }); 18 | 19 | test('should return correct code when headers are provided', () => { 20 | const options = { url: 'http://example.com', headers: { 'Content-Type': 'application/json' } }; 21 | const result = generateJavaCode(options); 22 | expect(result).toContain('conn.setRequestProperty("Content-Type", "application/json")'); 23 | }); 24 | 25 | test('should return correct code when query parameters are provided', () => { 26 | const options = { 27 | url: 'http://example.com', 28 | query: { 29 | param1: 'value1', 30 | arrayParam: ['value2', 'value3'] 31 | } 32 | }; 33 | const result = generateJavaCode(options); 34 | expect(result).toContain('params.add("param1", "value1")'); 35 | expect(result).toContain('params.add("arrayParam", "value2")'); 36 | expect(result).toContain('params.add("arrayParam", "value3")'); 37 | }); 38 | 39 | test('should return correct code when string body is provided', () => { 40 | const options = { url: 'http://example.com', body: 'Hello, World!' }; 41 | const result = generateJavaCode(options); 42 | expect(result).toContain('"Hello, World!".getBytes("utf-8")'); 43 | }); 44 | 45 | test('should return correct code when JSON body is provided', () => { 46 | const options = { 47 | url: 'http://example.com', 48 | body: new JsonBody({ 49 | key1: 'value1', 50 | key2: 'value2' 51 | }) 52 | }; 53 | const result = generateJavaCode(options); 54 | expect(result).toContain('String.format('); 55 | expect(result).toContain('"key1": "value1"'); 56 | expect(result).toContain('"key2": "value2"'); 57 | }); 58 | 59 | test('should return correct code when all options are provided', () => { 60 | const options = { 61 | url: 'http://example.com', 62 | method: 'POST', 63 | headers: { 'Content-Type': 'application/json' }, 64 | query: { param1: 'value1' }, 65 | body: new JsonBody({ key1: 'value1' }) 66 | }; 67 | const result = generateJavaCode(options); 68 | expect(result).toContain('conn.setRequestMethod("POST")'); 69 | expect(result).toContain('conn.setRequestProperty("Content-Type", "application/json")'); 70 | expect(result).toContain('params.add("param1", "value1")'); 71 | expect(result).toContain('String.format('); 72 | expect(result).toContain('"key1": "value1"'); 73 | }); 74 | }); -------------------------------------------------------------------------------- /src/generators/java.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptions, JsonBody } from "../request"; 2 | 3 | export function generateJavaCode(options: RequestOptions): string { 4 | function formatHeaders(headers: any): string { 5 | if (!headers) return ""; 6 | return Object.entries(headers) 7 | .map(([key, value]) => ` conn.setRequestProperty("${key}", "${value}");`) 8 | .join("\n"); 9 | } 10 | 11 | function formatQueryParams(query: any): string { 12 | if (!query) return ""; 13 | return Object.entries(query) 14 | .map(([key, value]) => { 15 | if (Array.isArray(value)) { 16 | return value.map(v => ` params.add("${key}", "${v}");`).join("\n"); 17 | } 18 | return ` params.add("${key}", "${value}");`; 19 | }) 20 | .join("\n"); 21 | } 22 | 23 | function formatJsonBody(body: string | JsonBody): string { 24 | if (!body) return ""; 25 | if (body instanceof JsonBody) { 26 | return JSON.stringify(body.body, null, 4) 27 | .split("\n") 28 | .map(line => " " + line) 29 | .join("\n"); 30 | } 31 | return body; 32 | } 33 | 34 | const code = `import java.io.BufferedReader; 35 | import java.io.InputStreamReader; 36 | import java.io.OutputStream; 37 | import java.net.HttpURLConnection; 38 | import java.net.URL; 39 | import java.net.URLEncoder; 40 | import java.nio.charset.StandardCharsets; 41 | import java.util.LinkedHashMap; 42 | import java.util.Map; 43 | 44 | public class Main { 45 | public static void main(String[] args) throws Exception { 46 | Map params = new LinkedHashMap<>(); 47 | ${formatQueryParams(options.query)} 48 | 49 | StringBuilder urlBuilder = new StringBuilder("${options.url}"); 50 | if (!params.isEmpty()) { 51 | urlBuilder.append("?"); 52 | boolean first = true; 53 | for (Map.Entry entry : params.entrySet()) { 54 | if (!first) { 55 | urlBuilder.append("&"); 56 | } 57 | urlBuilder.append(URLEncoder.encode(entry.getKey(), "UTF-8")); 58 | urlBuilder.append("="); 59 | urlBuilder.append(URLEncoder.encode(entry.getValue(), "UTF-8")); 60 | first = false; 61 | } 62 | } 63 | 64 | HttpURLConnection conn = (HttpURLConnection) new URL(urlBuilder.toString()).openConnection(); 65 | conn.setRequestMethod("${options.method || "GET"}"); 66 | ${formatHeaders(options.headers)} 67 | ${options.body ? ` 68 | conn.setDoOutput(true); 69 | try (OutputStream os = conn.getOutputStream()) { 70 | byte[] input = ${options.body instanceof JsonBody ? 71 | `String.format( 72 | ${formatJsonBody(options.body)} 73 | ).getBytes("utf-8")` : 74 | `"${options.body}".getBytes("utf-8")`}; 75 | os.write(input, 0, input.length); 76 | }` : ""} 77 | 78 | StringBuilder response = new StringBuilder(); 79 | try (BufferedReader br = new BufferedReader(new InputStreamReader( 80 | conn.getResponseCode() >= 400 ? conn.getErrorStream() : conn.getInputStream()))) { 81 | String line; 82 | while ((line = br.readLine()) != null) { 83 | response.append(line); 84 | } 85 | } 86 | conn.disconnect(); 87 | } 88 | } 89 | ` 90 | 91 | return code; 92 | } -------------------------------------------------------------------------------- /src/generators/javascript.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateJavaScriptCode } from "./javascript"; 3 | 4 | describe("generateJavaScriptCode", () => { 5 | test("should generate correct code with all options", () => { 6 | const options = { 7 | url: "https://example.com", 8 | query: { param1: "value1", param2: "value2" }, 9 | method: "POST", 10 | headers: { "Content-Type": "application/json" }, 11 | body: JSON.stringify({ key: "value" }), 12 | }; 13 | 14 | const expectedCode = `const params = new URLSearchParams({ 15 | param1: 'value1', 16 | param2: 'value2' 17 | }); 18 | 19 | const requestOptions = { 20 | method: 'POST', 21 | headers: { 22 | 'Content-Type': 'application/json' 23 | }, 24 | body: '{"key":"value"}', 25 | }; 26 | 27 | const response = await fetch('https://example.com' + '?' + params.toString(), requestOptions); 28 | `; 29 | 30 | expect(generateJavaScriptCode(options)).toBe(expectedCode); 31 | }); 32 | 33 | test("should generate correct code with only url", () => { 34 | const options = { 35 | url: "https://example.com", 36 | }; 37 | 38 | const expectedCode = `const params = new URLSearchParams({ 39 | }); 40 | 41 | const requestOptions = { 42 | }; 43 | 44 | const response = await fetch('https://example.com' + '?' + params.toString(), requestOptions); 45 | `; 46 | 47 | expect(generateJavaScriptCode(options)).toBe(expectedCode); 48 | }); 49 | 50 | test("should generate correct code with url and array query params", () => { 51 | const options = { 52 | url: "https://example.com", 53 | query: { tags: ["tag1", "tag2"] }, 54 | headers: { "Content-Type": "application/json" }, 55 | }; 56 | 57 | const expectedCode = `const params = new URLSearchParams({ 58 | tags: 'tag1', 59 | tags: 'tag2' 60 | }); 61 | 62 | const requestOptions = { 63 | headers: { 64 | 'Content-Type': 'application/json' 65 | }, 66 | }; 67 | 68 | const response = await fetch('https://example.com' + '?' + params.toString(), requestOptions); 69 | `; 70 | 71 | expect(generateJavaScriptCode(options)).toBe(expectedCode); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /src/generators/javascript.ts: -------------------------------------------------------------------------------- 1 | import { JsonBody, RequestOptions } from "../request"; 2 | 3 | export function generateJavaScriptCode(options: RequestOptions): string { 4 | let code = 'const params = new URLSearchParams({\n'; 5 | 6 | if (options.query) { 7 | code += Object.entries(options.query) 8 | .map(([key, value]) => { 9 | if (Array.isArray(value)) { 10 | return value.map(v => ` ${key}: '${v}'`).join(',\n'); 11 | } 12 | return ` ${key}: '${value}'`; 13 | }) 14 | .join(',\n'); 15 | code += '\n});\n\n'; 16 | } else { 17 | code += '});\n\n'; 18 | } 19 | 20 | code += `const requestOptions = {`; 21 | 22 | if (options.method) { 23 | code += `\n method: '${options.method}',`; 24 | } 25 | 26 | if (options.headers) { 27 | code += '\n headers: {\n'; 28 | code += Object.entries(options.headers) 29 | .map(([key, value]) => ` '${key}': '${value}'`) 30 | .join(',\n'); 31 | code += '\n },'; 32 | } 33 | 34 | if (options.body) { 35 | if (options.body instanceof JsonBody) { 36 | code += '\n body: ' + JSON.stringify(options.body.body, null, 4).replace(/^/gm, ' ') + ','; 37 | } else { 38 | // If not JSON, use as is 39 | code += `\n body: '${options.body}',`; 40 | } 41 | } 42 | 43 | code += '\n};\n\n'; 44 | 45 | code += `const response = await fetch('${options.url}' + '?' + params.toString(), requestOptions);\n`; 46 | 47 | return code; 48 | } 49 | -------------------------------------------------------------------------------- /src/generators/kotlin.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateKotlinCode } from "./kotlin"; 3 | import { generateComparableCode } from "../code"; 4 | import { JsonBody } from "../request"; 5 | 6 | describe("generateKotlinCode", () => { 7 | test("should return correct kotlin code with default method GET when no method is provided", () => { 8 | const options = { 9 | url: "http://test.com", 10 | }; 11 | const expectedCode = ` 12 | import java.net.URL 13 | import java.net.HttpURLConnection 14 | import com.google.gson.Gson 15 | 16 | fun makeRequest() { 17 | val gson = Gson() 18 | val params = mutableMapOf() 19 | val url = URL("http://test.com") 20 | val connection = url.openConnection() as HttpURLConnection 21 | connection.requestMethod = "GET" 22 | val response = connection.inputStream.bufferedReader().use { it.readText() } 23 | val responseCode = connection.responseCode 24 | if (responseCode != HttpURLConnection.HTTP_OK) { 25 | throw RuntimeException("HTTP error code: $responseCode") 26 | } 27 | } 28 | `; 29 | expect(generateComparableCode(generateKotlinCode(options))).toBe( 30 | generateComparableCode(expectedCode) 31 | ); 32 | }); 33 | 34 | test("should return correct kotlin code with provided method", () => { 35 | const options = { 36 | url: "http://test.com", 37 | method: "POST", 38 | }; 39 | const expectedCode = ` 40 | import java.net.URL 41 | import java.net.HttpURLConnection 42 | import com.google.gson.Gson 43 | 44 | fun makeRequest() { 45 | val gson = Gson() 46 | val params = mutableMapOf() 47 | val url = URL("http://test.com") 48 | val connection = url.openConnection() as HttpURLConnection 49 | connection.requestMethod = "POST" 50 | val response = connection.inputStream.bufferedReader().use { it.readText() } 51 | val responseCode = connection.responseCode 52 | if (responseCode != HttpURLConnection.HTTP_OK) { 53 | throw RuntimeException("HTTP error code: $responseCode") 54 | } 55 | } 56 | `; 57 | expect(generateComparableCode(generateKotlinCode(options))).toBe( 58 | generateComparableCode(expectedCode) 59 | ); 60 | }); 61 | 62 | test("should return correct kotlin code with provided headers", () => { 63 | const options = { 64 | url: "http://test.com", 65 | headers: { 66 | "Content-Type": "application/json", 67 | }, 68 | }; 69 | const expectedCode = ` 70 | import java.net.URL 71 | import java.net.HttpURLConnection 72 | import com.google.gson.Gson 73 | 74 | fun makeRequest() { 75 | val gson = Gson() 76 | val params = mutableMapOf() 77 | val url = URL("http://test.com") 78 | val connection = url.openConnection() as HttpURLConnection 79 | connection.requestMethod = "GET" 80 | connection.setRequestProperty("Content-Type", "application/json") 81 | val response = connection.inputStream.bufferedReader().use { it.readText() } 82 | val responseCode = connection.responseCode 83 | if (responseCode != HttpURLConnection.HTTP_OK) { 84 | throw RuntimeException("HTTP error code: $responseCode") 85 | } 86 | } 87 | `; 88 | expect(generateComparableCode(generateKotlinCode(options))).toBe( 89 | generateComparableCode(expectedCode) 90 | ); 91 | }); 92 | 93 | test("should return correct kotlin code with provided JSON body", () => { 94 | const options = { 95 | url: "http://test.com", 96 | method: "POST", 97 | body: new JsonBody({ key: "value", number: 42 }), 98 | }; 99 | const expectedCode = ` 100 | import java.net.URL 101 | import java.net.HttpURLConnection 102 | import com.google.gson.Gson 103 | 104 | fun makeRequest() { 105 | val gson = Gson() 106 | val params = mutableMapOf() 107 | val url = URL("http://test.com") 108 | val connection = url.openConnection() as HttpURLConnection 109 | connection.requestMethod = "POST" 110 | val requestBody = mapOf( 111 | "key" to "value", 112 | "number" to "42" 113 | ) 114 | val jsonBody = gson.toJson(requestBody) 115 | connection.setRequestProperty("Content-Type", "application/json") 116 | connection.outputStream.use { os -> 117 | os.write(jsonBody.toByteArray()) 118 | } 119 | val response = connection.inputStream.bufferedReader().use { it.readText() } 120 | val responseCode = connection.responseCode 121 | if (responseCode != HttpURLConnection.HTTP_OK) { 122 | throw RuntimeException("HTTP error code: $responseCode") 123 | } 124 | } 125 | `; 126 | expect(generateComparableCode(generateKotlinCode(options))).toBe( 127 | generateComparableCode(expectedCode) 128 | ); 129 | }); 130 | 131 | test("should return correct kotlin code with provided query parameters", () => { 132 | const options = { 133 | url: "http://test.com", 134 | query: { 135 | param1: "value1", 136 | param2: ["value2", "value3"], 137 | }, 138 | }; 139 | const expectedCode = ` 140 | import java.net.URL 141 | import java.net.HttpURLConnection 142 | import com.google.gson.Gson 143 | 144 | fun makeRequest() { 145 | val gson = Gson() 146 | val params = mutableMapOf() 147 | params["param1"] = "value1" 148 | params["param2"] = "value2" 149 | params["param2"] = "value3" 150 | val url = URL("http://test.com?\${params.entries.joinToString("&") { "\${it.key}=\${it.value}" }}") 151 | val connection = url.openConnection() as HttpURLConnection 152 | connection.requestMethod = "GET" 153 | val response = connection.inputStream.bufferedReader().use { it.readText() } 154 | val responseCode = connection.responseCode 155 | if (responseCode != HttpURLConnection.HTTP_OK) { 156 | throw RuntimeException("HTTP error code: $responseCode") 157 | } 158 | } 159 | `; 160 | expect(generateComparableCode(generateKotlinCode(options))).toBe( 161 | generateComparableCode(expectedCode) 162 | ); 163 | }); 164 | }); 165 | -------------------------------------------------------------------------------- /src/generators/kotlin.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptions, JsonBody } from "../request"; 2 | 3 | export function generateKotlinCode(options: RequestOptions): string { 4 | function formatHeaders(headers: any): string { 5 | if (!headers) return ""; 6 | return Object.entries(headers) 7 | .map(([key, value]) => ` connection.setRequestProperty("${key}", "${value}")`) 8 | .join("\n"); 9 | } 10 | 11 | function formatQueryParams(query: any): string { 12 | if (!query) return ""; 13 | return Object.entries(query) 14 | .map(([key, value]) => { 15 | if (Array.isArray(value)) { 16 | return value.map(v => ` params["${key}"] = "${v}"`).join("\n"); 17 | } 18 | return ` params["${key}"] = "${value}"`; 19 | }) 20 | .join("\n"); 21 | } 22 | 23 | function formatBody(body: string | JsonBody | undefined): string { 24 | if (!body) return ""; 25 | if (body instanceof JsonBody) { 26 | return ` val requestBody = mapOf( 27 | ${Object.entries(body.body) 28 | .map(([key, value]) => ` "${key}" to "${value}"`) 29 | .join(",\n")} 30 | ) 31 | val jsonBody = gson.toJson(requestBody) 32 | connection.setRequestProperty("Content-Type", "application/json") 33 | connection.outputStream.use { os -> 34 | os.write(jsonBody.toByteArray()) 35 | }`; 36 | } 37 | return ` connection.outputStream.use { os -> 38 | os.write("""${body}""".toByteArray()) 39 | }`; 40 | } 41 | 42 | const code = `import java.net.URL 43 | import java.net.HttpURLConnection 44 | import com.google.gson.Gson 45 | 46 | fun makeRequest() { 47 | val gson = Gson() 48 | val params = mutableMapOf() 49 | ${options.query ? formatQueryParams(options.query) : ""} 50 | val url = URL("${options.url}${options.query ? "?" + "\${params.entries.joinToString(\"&\") { \"\${it.key}=\${it.value}\" }}" : ""}") 51 | val connection = url.openConnection() as HttpURLConnection 52 | connection.requestMethod = "${options.method || "GET"}" 53 | ${formatHeaders(options.headers)} 54 | ${options.body ? formatBody(options.body) : ""} 55 | val response = connection.inputStream.bufferedReader().use { it.readText() } 56 | val responseCode = connection.responseCode 57 | if (responseCode != HttpURLConnection.HTTP_OK) { 58 | throw RuntimeException("HTTP error code: $responseCode") 59 | } 60 | }`; 61 | 62 | return code; 63 | } -------------------------------------------------------------------------------- /src/generators/node-axios.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateNodeAxiosCode } from "./node-axios"; 3 | 4 | describe("generateNodeAxiosCode", () => { 5 | test("should generate axios code with default method", () => { 6 | const options = { 7 | url: "http://test.com", 8 | }; 9 | const expectedCode = `const axios = require('axios'); 10 | 11 | axios({ 12 | method: 'GET', 13 | url: 'http://test.com' 14 | }) 15 | .then(response => response) 16 | .catch(error => { 17 | throw error; 18 | });`; 19 | expect(generateNodeAxiosCode(options)).toBe(expectedCode); 20 | }); 21 | 22 | test("should generate axios code with provided method", () => { 23 | const options = { 24 | url: "http://test.com", 25 | method: "POST", 26 | }; 27 | const expectedCode = `const axios = require('axios'); 28 | 29 | axios({ 30 | method: 'POST', 31 | url: 'http://test.com' 32 | }) 33 | .then(response => response) 34 | .catch(error => { 35 | throw error; 36 | });`; 37 | expect(generateNodeAxiosCode(options)).toBe(expectedCode); 38 | }); 39 | 40 | test("should generate axios code with query parameters", () => { 41 | const options = { 42 | url: "http://test.com", 43 | query: { param1: "value1", param2: "value2" }, 44 | }; 45 | const expectedCode = `const axios = require('axios'); 46 | 47 | axios({ 48 | method: 'GET', 49 | url: 'http://test.com', 50 | params: { 51 | "param1": "value1", 52 | "param2": "value2" 53 | } 54 | }) 55 | .then(response => response) 56 | .catch(error => { 57 | throw error; 58 | });`; 59 | expect(generateNodeAxiosCode(options)).toBe(expectedCode); 60 | }); 61 | 62 | test("should generate axios code with headers", () => { 63 | const options = { 64 | url: "http://test.com", 65 | headers: { "Content-Type": "application/json" }, 66 | }; 67 | const expectedCode = `const axios = require('axios'); 68 | 69 | axios({ 70 | method: 'GET', 71 | url: 'http://test.com', 72 | headers: { 73 | "Content-Type": "application/json" 74 | } 75 | }) 76 | .then(response => response) 77 | .catch(error => { 78 | throw error; 79 | });`; 80 | expect(generateNodeAxiosCode(options)).toBe(expectedCode); 81 | }); 82 | 83 | test("should generate axios code with body", () => { 84 | const options = { 85 | url: "http://test.com", 86 | method: "POST", 87 | body: JSON.stringify({ key: "value", nested: { prop: "test" } }), 88 | }; 89 | const expectedCode = `const axios = require('axios'); 90 | 91 | axios({ 92 | method: 'POST', 93 | url: 'http://test.com', 94 | data: { 95 | "key": "value", 96 | "nested": {"prop":"test"} 97 | } 98 | }) 99 | .then(response => response) 100 | .catch(error => { 101 | throw error; 102 | });`; 103 | expect(generateNodeAxiosCode(options)).toBe(expectedCode); 104 | }); 105 | 106 | test("should generate axios code with array in query parameters", () => { 107 | const options = { 108 | url: "http://test.com", 109 | query: { tags: ["tag1", "tag2"], filter: "active" }, 110 | }; 111 | const expectedCode = `const axios = require('axios'); 112 | 113 | axios({ 114 | method: 'GET', 115 | url: 'http://test.com', 116 | params: { 117 | "tags": ["tag1","tag2"], 118 | "filter": "active" 119 | } 120 | }) 121 | .then(response => response) 122 | .catch(error => { 123 | throw error; 124 | });`; 125 | expect(generateNodeAxiosCode(options)).toBe(expectedCode); 126 | }); 127 | }); 128 | -------------------------------------------------------------------------------- /src/generators/node-axios.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptions } from "../request"; 2 | 3 | export function generateNodeAxiosCode(options: RequestOptions): string { 4 | function formatObject(obj: any): string { 5 | if (!obj) return ''; 6 | const entries = Object.entries(obj); 7 | if (entries.length === 0) return '{}'; 8 | 9 | return `{\n${entries.map(([key, value]) => ` ${JSON.stringify(key)}: ${JSON.stringify(value)}`).join(',\n')}\n}`; 10 | } 11 | 12 | function formatRequestOptions(): string { 13 | const opts = [` method: '${options.method || 'GET'}'`, ` url: '${options.url}'`]; 14 | 15 | if (options.query) { 16 | opts.push(` params: ${formatObject(options.query)}`); 17 | } 18 | 19 | if (options.headers) { 20 | opts.push(` headers: ${formatObject(options.headers)}`); 21 | } 22 | 23 | if (options.body) { 24 | const bodyData = typeof options.body === 'string' ? JSON.parse(options.body) : options.body; 25 | opts.push(` data: ${formatObject(bodyData)}`); 26 | } 27 | 28 | return opts.join(',\n'); 29 | } 30 | 31 | return `const axios = require('axios'); 32 | 33 | axios({ 34 | ${formatRequestOptions()} 35 | }) 36 | .then(response => response) 37 | .catch(error => { 38 | throw error; 39 | });`; 40 | } -------------------------------------------------------------------------------- /src/generators/node-fetch.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateNodeFetchCode } from "./node-fetch"; 3 | import { JsonBody } from "../request"; 4 | 5 | describe('generateNodeFetchCode', () => { 6 | test('should generate code with GET method by default', () => { 7 | const options = { url: 'https://example.com' }; 8 | const result = generateNodeFetchCode(options); 9 | expect(result).toContain("method: 'GET'"); 10 | expect(result).toContain("const response = await fetch"); 11 | expect(result).toContain("const data = await response.json()"); 12 | }); 13 | 14 | test('should generate code with provided method', () => { 15 | const options = { url: 'https://example.com', method: 'POST' }; 16 | const result = generateNodeFetchCode(options); 17 | expect(result).toContain("method: 'POST'"); 18 | }); 19 | 20 | test('should generate code with provided headers', () => { 21 | const options = { 22 | url: 'https://example.com', 23 | headers: { 24 | 'Content-Type': 'application/json', 25 | 'Authorization': 'Bearer token' 26 | } 27 | }; 28 | const result = generateNodeFetchCode(options); 29 | expect(result).toContain("'Content-Type': 'application/json'"); 30 | expect(result).toContain("'Authorization': 'Bearer token'"); 31 | }); 32 | 33 | test('should generate code with provided string body', () => { 34 | const options = { url: 'https://example.com', body: 'test body' }; 35 | const result = generateNodeFetchCode(options); 36 | expect(result).toContain("body: 'test body'"); 37 | }); 38 | 39 | test('should generate code with provided JSON body', () => { 40 | const options = { 41 | url: 'https://example.com', 42 | body: new JsonBody({ 43 | key1: 'value1', 44 | key2: 'value2' 45 | }) 46 | }; 47 | const result = generateNodeFetchCode(options); 48 | expect(result).toContain('"key1": "value1"'); 49 | expect(result).toContain('"key2": "value2"'); 50 | }); 51 | 52 | test('should generate code with provided query parameters', () => { 53 | const options = { 54 | url: 'https://example.com', 55 | query: { 56 | param1: 'value1', 57 | param2: ['value2', 'value3'], 58 | param3: '123' 59 | } 60 | }; 61 | const result = generateNodeFetchCode(options); 62 | expect(result).toContain("const params = {"); 63 | expect(result).toContain('"param1": "value1"'); 64 | expect(result).toContain('"param2": [\n "value2",\n "value3"\n ]'); 65 | expect(result).toContain('"param3": "123"'); 66 | expect(result).toContain("new URLSearchParams(params).toString()"); 67 | }); 68 | }); -------------------------------------------------------------------------------- /src/generators/node-fetch.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptions, JsonBody } from "../request"; 2 | 3 | export function generateNodeFetchCode(options: RequestOptions): string { 4 | const queryParams = options.query ? `\n ${JSON.stringify(options.query, null, 4).replace(/^{/, '').replace(/}$/, '').trim()}\n` : ''; 5 | const bodyContent = options.body instanceof JsonBody ? 6 | `\n ${JSON.stringify(options.body.body, null, 4).replace(/^{/, '').replace(/}$/, '').trim()}\n` : 7 | options.body; 8 | 9 | const code = `const fetch = require('node-fetch'); 10 | 11 | const params = {${queryParams}}; 12 | const url = '${options.url}' + (Object.keys(params).length ? '?' + new URLSearchParams(params).toString() : ''); 13 | 14 | const options = { 15 | method: '${options.method || "GET"}'${options.headers ? `, 16 | headers: { 17 | ${Object.entries(options.headers).map(([key, value]) => `'${key}': '${value}'`).join(',\n ')} 18 | }` : ''}${bodyContent ? `, 19 | body: ${options.body instanceof JsonBody ? `{${bodyContent}}` : `'${bodyContent}'`}` : ''} 20 | }; 21 | 22 | const response = await fetch(url, options); 23 | const data = await response.json();`; 24 | 25 | return code; 26 | } 27 | -------------------------------------------------------------------------------- /src/generators/node-http.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateNodeHTTPCode } from "./node-http"; 3 | import { generateComparableCode } from "../code"; 4 | import { JsonBody } from "../request"; 5 | 6 | describe("generateNodeHTTPCode", () => { 7 | test("should generate correct code with GET method and no query", () => { 8 | const options = { 9 | url: "http://localhost/test", 10 | method: "GET", 11 | }; 12 | const expectedCode = `const http = require('http'); 13 | 14 | const options = { 15 | hostname: 'localhost', 16 | port: 80, 17 | path: '/test', 18 | method: 'GET', 19 | headers: {} 20 | }; 21 | 22 | let response = ''; 23 | const req = http.request(options, (res) => { 24 | res.on('data', (chunk) => { 25 | response += chunk; 26 | }); 27 | }); 28 | 29 | req.on('error', (error) => { 30 | console.error(error); 31 | }); 32 | 33 | req.end();`; 34 | expect(generateComparableCode(generateNodeHTTPCode(options))).toBe( 35 | generateComparableCode(expectedCode) 36 | ); 37 | }); 38 | 39 | test("should generate correct code with POST method and query parameters", () => { 40 | const options = { 41 | url: "http://localhost/test", 42 | method: "POST", 43 | query: { key: "value", array: ["item1", "item2"] }, 44 | body: new JsonBody({ data: "example" }), 45 | }; 46 | const expectedCode = `const http = require('http'); 47 | const querystring = require('querystring'); 48 | 49 | const query = { 50 | key: "value", 51 | array: ["item1","item2"] 52 | }; 53 | 54 | const body = { 55 | data: "example" 56 | }; 57 | 58 | const options = { 59 | hostname: 'localhost', 60 | port: 80, 61 | path: '/test'+'?'+querystring.stringify(query), 62 | method: 'POST', 63 | headers: {} 64 | }; 65 | 66 | let response = ''; 67 | const req = http.request(options, (res) => { 68 | res.on('data', (chunk) => { 69 | response += chunk; 70 | }); 71 | }); 72 | 73 | req.on('error', (error) => { 74 | console.error(error); 75 | }); 76 | 77 | req.write(JSON.stringify(body)); 78 | req.end();`; 79 | expect(generateComparableCode(generateNodeHTTPCode(options))).toBe( 80 | generateComparableCode(expectedCode) 81 | ); 82 | }); 83 | 84 | test("should generate correct code with HTTPS", () => { 85 | const options = { 86 | url: "https://api.example.com/test", 87 | headers: { "Content-Type": "application/json" }, 88 | }; 89 | const expectedCode = `const https = require('https'); 90 | 91 | const options = { 92 | hostname: 'api.example.com', 93 | port: 443, 94 | path: '/test', 95 | method: 'GET', 96 | headers: {"Content-Type":"application/json"} 97 | }; 98 | 99 | let response = ''; 100 | const req = https.request(options, (res) => { 101 | res.on('data', (chunk) => { 102 | response += chunk; 103 | }); 104 | }); 105 | 106 | req.on('error', (error) => { 107 | console.error(error); 108 | }); 109 | 110 | req.end();`; 111 | expect(generateComparableCode(generateNodeHTTPCode(options))).toBe( 112 | generateComparableCode(expectedCode) 113 | ); 114 | }); 115 | 116 | test("should generate correct code with non-JSON body", () => { 117 | const options = { 118 | url: "http://localhost/test", 119 | method: "POST", 120 | body: "raw body content", 121 | }; 122 | const expectedCode = `const http = require('http'); 123 | 124 | const body = "raw body content"; 125 | 126 | const options = { 127 | hostname: 'localhost', 128 | port: 80, 129 | path: '/test', 130 | method: 'POST', 131 | headers: {} 132 | }; 133 | 134 | let response = ''; 135 | const req = http.request(options, (res) => { 136 | res.on('data', (chunk) => { 137 | response += chunk; 138 | }); 139 | }); 140 | 141 | req.on('error', (error) => { 142 | console.error(error); 143 | }); 144 | 145 | req.write(body); 146 | req.end();`; 147 | expect(generateComparableCode(generateNodeHTTPCode(options))).toBe( 148 | generateComparableCode(expectedCode) 149 | ); 150 | }); 151 | }); 152 | -------------------------------------------------------------------------------- /src/generators/node-http.ts: -------------------------------------------------------------------------------- 1 | import { JsonBody, RequestOptions } from "../request"; 2 | 3 | export function generateNodeHTTPCode(options: RequestOptions): string { 4 | const url = new URL(options.url); 5 | const isHttps = url.protocol === "https:"; 6 | const defaultPort = isHttps ? 443 : 80; 7 | 8 | // Format query parameters as a proper object if present 9 | let queryObject = ""; 10 | if (options.query && Object.keys(options.query).length > 0) { 11 | queryObject = `const query = {\n ${Object.entries(options.query) 12 | .map(([key, value]) => `${key}: ${JSON.stringify(value)}`) 13 | .join(",\n ")}\n};\n\n`; 14 | } 15 | 16 | // Format body as a proper JSON object if it's JSON 17 | let bodyObject = ""; 18 | if (options.body) { 19 | if (options.body instanceof JsonBody) { 20 | const parsedBody = options.body.body; 21 | if (typeof parsedBody === "object") { 22 | bodyObject = `const body = {\n ${Object.entries(parsedBody) 23 | .map(([key, value]) => `${key}: ${JSON.stringify(value)}`) 24 | .join(",\n ")}\n};\n\n`; 25 | } 26 | } else { 27 | // If not JSON, use as is 28 | bodyObject = `const body = ${JSON.stringify(options.body)};\n\n`; 29 | } 30 | } 31 | 32 | const code = `const ${isHttps ? "https" : "http"} = require('${ 33 | isHttps ? "https" : "http" 34 | }'); 35 | ${ 36 | options.query ? "const querystring = require('querystring');\n" : "" 37 | }${queryObject}${bodyObject}const options = { 38 | hostname: '${url.hostname}', 39 | port: ${url.port || defaultPort}, 40 | path: '${url.pathname}'${ 41 | options.query ? " + '?' + querystring.stringify(query)" : "" 42 | }, 43 | method: '${options.method || "GET"}', 44 | headers: ${JSON.stringify(options.headers || {})} 45 | }; 46 | 47 | let response = ''; 48 | const req = ${isHttps ? "https" : "http"}.request(options, (res) => { 49 | res.on('data', (chunk) => { 50 | response += chunk; 51 | }); 52 | }); 53 | 54 | req.on('error', (error) => { 55 | console.error(error); 56 | }); 57 | ${ 58 | options.body 59 | ? options.body instanceof JsonBody 60 | ? "\nreq.write(JSON.stringify(body));" 61 | : "\nreq.write(body);" 62 | : "" 63 | } 64 | req.end();`; 65 | 66 | return code; 67 | } 68 | -------------------------------------------------------------------------------- /src/generators/objective-c.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateObjectiveCCode } from "./objective-c"; 3 | import { JsonBody } from "../request"; 4 | 5 | describe('generateObjectiveCCode', () => { 6 | test('should return correct code when only url is provided', () => { 7 | const options = { url: 'https://example.com' }; 8 | const result = generateObjectiveCCode(options); 9 | expect(result).toContain('NSURL *url = [NSURL URLWithString:@"https://example.com"]'); 10 | expect(result).toContain('\nNSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]'); 11 | }); 12 | 13 | test('should return correct code when headers are provided', () => { 14 | const options = { url: 'https://example.com', headers: { 'Content-Type': 'application/json' } }; 15 | const result = generateObjectiveCCode(options); 16 | expect(result).toContain('NSDictionary *headers = @{\n @"Content-Type": @"application/json"\n};'); 17 | expect(result).toContain('\n[headers enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop)'); 18 | }); 19 | 20 | test('should return correct code when method is provided', () => { 21 | const options = { url: 'https://example.com', method: 'POST' }; 22 | const result = generateObjectiveCCode(options); 23 | expect(result).toContain('[request setHTTPMethod:@"POST"]'); 24 | }); 25 | 26 | test('should return correct code when string body is provided', () => { 27 | const options = { url: 'https://example.com', body: 'test body' }; 28 | const result = generateObjectiveCCode(options); 29 | expect(result).toContain('NSString *httpBodyString = @"test body";\n[request setHTTPBody:[httpBodyString dataUsingEncoding:NSUTF8StringEncoding]];'); 30 | }); 31 | 32 | test('should return correct code when JSON body is provided as string', () => { 33 | const options = { url: 'https://example.com', body: '{"key":"value","number":42}' }; 34 | const result = generateObjectiveCCode(options); 35 | expect(result).toContain('NSString *httpBodyString = @"{\"key\":\"value\",\"number\":42}";'); 36 | expect(result).toContain('[request setHTTPBody:[httpBodyString dataUsingEncoding:NSUTF8StringEncoding]];'); 37 | }); 38 | 39 | test('should return correct code when JSON body is provided as object', () => { 40 | const options = { 41 | url: 'https://example.com', 42 | body: new JsonBody({ key: 'value', nested: { prop: true }, array: [1, 2, 3] }) 43 | }; 44 | const result = generateObjectiveCCode(options); 45 | expect(result).toContain('NSDictionary *httpBody = @{\n @"key": @"value",\n @"nested": @{\n @"prop": @YES\n },\n @"array": @[@1, @2, @3]\n};'); 46 | expect(result).toContain('\nNSData *httpBodyData = [NSJSONSerialization dataWithJSONObject:httpBody options:0 error:nil]'); 47 | }); 48 | 49 | test('should return correct code when all options are provided', () => { 50 | const options = { 51 | url: 'https://example.com', 52 | headers: { 'Content-Type': 'application/json' }, 53 | method: 'POST', 54 | body: new JsonBody({ test: 'body' }) 55 | }; 56 | const result = generateObjectiveCCode(options); 57 | expect(result).toContain('NSURL *url = [NSURL URLWithString:@"https://example.com"]'); 58 | expect(result).toContain('\nNSDictionary *headers = @{\n @"Content-Type": @"application/json"\n};'); 59 | expect(result).toContain('[request setHTTPMethod:@"POST"]'); 60 | expect(result).toContain('NSDictionary *httpBody = @{\n @"test": @"body"\n};'); 61 | expect(result).toContain('\nNSData *httpBodyData = [NSJSONSerialization dataWithJSONObject:httpBody options:0 error:nil]'); 62 | }); 63 | 64 | test('should return correct code when query parameters are provided', () => { 65 | const options = { 66 | url: 'https://example.com', 67 | query: { 68 | key: 'value', 69 | numbers: ['42', '43'], 70 | flags: ['true', 'false'] 71 | } 72 | }; 73 | const result = generateObjectiveCCode(options); 74 | expect(result).toContain('NSURLComponents *components = [[NSURLComponents alloc] initWithString:@"https://example.com"]'); 75 | expect(result).toContain('NSMutableArray *queryItems = [NSMutableArray array]'); 76 | expect(result).toContain('[queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"key" value:@"value"]]'); 77 | expect(result).toContain('[queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"numbers" value:@"42"]]'); 78 | expect(result).toContain('[queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"numbers" value:@"43"]]'); 79 | expect(result).toContain('[queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"flags" value:@"true"]]'); 80 | expect(result).toContain('[queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"flags" value:@"false"]]'); 81 | expect(result).toContain('[components setQueryItems:queryItems]'); 82 | expect(result).toContain('NSURL *url = [components URL]'); 83 | }); 84 | 85 | test('should return correct code when query parameters contain empty values', () => { 86 | const options = { 87 | url: 'https://example.com', 88 | query: { 89 | empty: '', 90 | array: [] 91 | } 92 | }; 93 | const result = generateObjectiveCCode(options); 94 | expect(result).toContain('[queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"empty" value:@""]]'); 95 | }); 96 | 97 | test('should return correct code when query parameters contain special characters', () => { 98 | const options = { 99 | url: 'https://example.com', 100 | query: { 101 | 'special chars': 'value with spaces', 102 | 'encoded[]': ['value1', 'value2'] 103 | } 104 | }; 105 | const result = generateObjectiveCCode(options); 106 | expect(result).toContain('[queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"special chars" value:@"value with spaces"]]'); 107 | expect(result).toContain('[queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"encoded[]" value:@"value1"]]'); 108 | expect(result).toContain('[queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"encoded[]" value:@"value2"]]'); 109 | }); 110 | }); -------------------------------------------------------------------------------- /src/generators/objective-c.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptions, JsonBody } from "../request"; 2 | 3 | export function generateObjectiveCCode(options: RequestOptions): string { 4 | const headers = options.headers ? Object.entries(options.headers) : []; 5 | let bodyCode = ""; 6 | let urlCode = ""; 7 | 8 | // Handle query parameters 9 | if (options.query && Object.keys(options.query).length > 0) { 10 | urlCode = `NSURLComponents *components = [[NSURLComponents alloc] initWithString:@"${options.url}"]; 11 | NSMutableArray *queryItems = [NSMutableArray array]; 12 | ${Object.entries(options.query) 13 | .map(([key, value]) => { 14 | if (Array.isArray(value)) { 15 | return value.map(v => `[queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"${key}" value:${formatObjectiveCValue(v)}]];`).join("\n"); 16 | } 17 | return `[queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"${key}" value:${formatObjectiveCValue(value)}]];`; 18 | }) 19 | .join("\n")} 20 | [components setQueryItems:queryItems]; 21 | NSURL *url = [components URL];`; 22 | } else { 23 | urlCode = `NSURL *url = [NSURL URLWithString:@"${options.url}"];`; 24 | } 25 | 26 | if (options.body) { 27 | if (options.body instanceof JsonBody) { 28 | bodyCode = `NSDictionary *httpBody = @{${Object.entries(options.body.body) 29 | .map(([key, value]) => `\n @"${key}": ${formatObjectiveCValue(value)}`) 30 | .join(",")} 31 | }; 32 | 33 | NSData *httpBodyData = [NSJSONSerialization dataWithJSONObject:httpBody options:0 error:nil]; 34 | [request setHTTPBody:httpBodyData];`; 35 | } else { 36 | bodyCode = `NSString *httpBodyString = @"${options.body}"; 37 | [request setHTTPBody:[httpBodyString dataUsingEncoding:NSUTF8StringEncoding]];`; 38 | } 39 | } 40 | 41 | const code = `${urlCode} 42 | 43 | NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; 44 | [request setCachePolicy:NSURLRequestUseProtocolCachePolicy]; 45 | [request setTimeoutInterval:10.0]; 46 | [request setHTTPMethod:@"${options.method || "GET"}"]; 47 | ${headers.length > 0 ? ` 48 | NSDictionary *headers = @{${headers.map(([key, value]) => `\n @"${key}": @"${value}"`).join(",")} 49 | }; 50 | 51 | [headers enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { 52 | [request setValue:value forHTTPHeaderField:key]; 53 | }];` : ""}${bodyCode ? `\n${bodyCode}` : ""} 54 | 55 | NSURLSession *session = [NSURLSession sharedSession]; 56 | NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 57 | NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; 58 | }]; 59 | [task resume];`; 60 | 61 | return code; 62 | } 63 | 64 | function formatObjectiveCValue(value: any): string { 65 | if (typeof value === "string") { 66 | return `@"${value}"`; 67 | } else if (typeof value === "number") { 68 | return `@${value}`; 69 | } else if (typeof value === "boolean") { 70 | return value ? `@YES` : `@NO`; 71 | } else if (Array.isArray(value)) { 72 | return `@[${value.map((v) => formatObjectiveCValue(v)).join(", ")}]`; 73 | } else if (value === null) { 74 | return `[NSNull null]`; 75 | } else if (typeof value === "object") { 76 | const entries = Object.entries(value); 77 | if (entries.length === 0) return `@{}`; 78 | return `@{${entries.map(([k, v]) => `\n @"${k}": ${formatObjectiveCValue(v)}`).join(",")}\n }`; 79 | } 80 | return `@""`; 81 | } 82 | -------------------------------------------------------------------------------- /src/generators/php-guzzle.test.ts: -------------------------------------------------------------------------------- 1 | import { generatePHPGuzzleCode } from "./php-guzzle"; 2 | import { JsonBody } from "../request"; 3 | 4 | describe("generatePHPGuzzleCode", () => { 5 | test("generates code for GET request", () => { 6 | const code = generatePHPGuzzleCode({ 7 | method: "GET", 8 | url: "https://api.example.com/users", 9 | }); 10 | expect(code).toBe(`request('GET', 'https://api.example.com/users', $requestOptions); 20 | } catch (\\GuzzleHttp\\Exception\\RequestException $e) { 21 | $error = $e->getMessage(); 22 | }`); 23 | }); 24 | 25 | test("generates code for POST request with JSON body", () => { 26 | const code = generatePHPGuzzleCode({ 27 | method: "POST", 28 | url: "https://api.example.com/users", 29 | body: new JsonBody({ name: "John", age: 30 }), 30 | }); 31 | expect(code).toBe(` "John", 41 | 'age' => 30, 42 | ]; 43 | 44 | try { 45 | $response = $client->request('POST', 'https://api.example.com/users', $requestOptions); 46 | } catch (\\GuzzleHttp\\Exception\\RequestException $e) { 47 | $error = $e->getMessage(); 48 | }`); 49 | }); 50 | 51 | test("generates code for PUT request with headers", () => { 52 | const code = generatePHPGuzzleCode({ 53 | method: "PUT", 54 | url: "https://api.example.com/users/1", 55 | headers: { 56 | "Content-Type": "application/json", 57 | "Authorization": "Bearer token123", 58 | }, 59 | body: new JsonBody({ name: "Updated John" }), 60 | }); 61 | expect(code).toBe(` 'application/json', 71 | 'Authorization' => 'Bearer token123', 72 | ]; 73 | 74 | $requestOptions['json'] = [ 75 | 'name' => "Updated John", 76 | ]; 77 | 78 | try { 79 | $response = $client->request('PUT', 'https://api.example.com/users/1', $requestOptions); 80 | } catch (\\GuzzleHttp\\Exception\\RequestException $e) { 81 | $error = $e->getMessage(); 82 | }`); 83 | }); 84 | 85 | test("generates code for DELETE request", () => { 86 | const code = generatePHPGuzzleCode({ 87 | method: "DELETE", 88 | url: "https://api.example.com/users/1", 89 | }); 90 | expect(code).toBe(`request('DELETE', 'https://api.example.com/users/1', $requestOptions); 100 | } catch (\\GuzzleHttp\\Exception\\RequestException $e) { 101 | $error = $e->getMessage(); 102 | }`); 103 | }); 104 | 105 | test("generates code for PATCH request with query parameters", () => { 106 | const code = generatePHPGuzzleCode({ 107 | method: "PATCH", 108 | url: "https://api.example.com/users/1", 109 | query: { 110 | version: "2", 111 | fields: ["name", "email"], 112 | }, 113 | body: new JsonBody({ status: "inactive" }), 114 | }); 115 | expect(code).toBe(` '2', 125 | 'fields[]' => 'name', 126 | 'fields[]' => 'email', 127 | ]; 128 | 129 | $requestOptions['json'] = [ 130 | 'status' => "inactive", 131 | ]; 132 | 133 | try { 134 | $response = $client->request('PATCH', 'https://api.example.com/users/1', $requestOptions); 135 | } catch (\\GuzzleHttp\\Exception\\RequestException $e) { 136 | $error = $e->getMessage(); 137 | }`); 138 | }); 139 | }); 140 | -------------------------------------------------------------------------------- /src/generators/php-guzzle.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptions, JsonBody } from "../request"; 2 | 3 | export function generatePHPGuzzleCode(options: RequestOptions): string { 4 | let code = ` '${value}',`; 16 | } 17 | code += `\n];`; 18 | } 19 | 20 | if (options.query) { 21 | code += `\n\n$requestOptions['query'] = [`; 22 | for (const [key, value] of Object.entries(options.query)) { 23 | if (Array.isArray(value)) { 24 | for (const v of value) { 25 | code += `\n '${key}[]' => '${v}',`; 26 | } 27 | } else { 28 | code += `\n '${key}' => '${value}',`; 29 | } 30 | } 31 | code += `\n];`; 32 | } 33 | 34 | if (options.body) { 35 | if (options.body instanceof JsonBody) { 36 | code += `\n\n$requestOptions['json'] = [`; 37 | for (const [key, value] of Object.entries(options.body.body)) { 38 | code += `\n '${key}' => ${JSON.stringify(value)},`; 39 | } 40 | code += `\n];`; 41 | } else { 42 | code += `\n\n$requestOptions['body'] = '${options.body}';`; 43 | } 44 | } 45 | 46 | code += `\n\ntry { 47 | $response = $client->request('${options.method || "GET"}', '${options.url}', $requestOptions); 48 | } catch (\\GuzzleHttp\\Exception\\RequestException $e) { 49 | $error = $e->getMessage(); 50 | }`; 51 | 52 | return code; 53 | } 54 | -------------------------------------------------------------------------------- /src/generators/php-requests.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generatePHPRequestsCode } from "./php-requests"; 3 | import { JsonBody } from "../request"; 4 | 5 | describe("generatePHPRequestsCode", () => { 6 | test("should generate correct PHP code with GET method", () => { 7 | const options = { 8 | method: "GET", 9 | url: "https://example.com", 10 | headers: { "Content-Type": "application/json" }, 11 | query: { key: "value" }, 12 | }; 13 | const result = generatePHPRequestsCode(options); 14 | expect(result).toContain(`$method = 'GET';`); 15 | expect(result).toContain(`$url = 'https://example.com';`); 16 | expect(result).toContain(`$headers = [ 17 | 'Content-Type' => 'application/json' 18 | ]`); 19 | expect(result).toContain(`$query = [ 20 | 'key' => 'value' 21 | ]`); 22 | expect(result).toContain(`$body = [];`); 23 | }); 24 | 25 | test("should generate correct PHP code with POST method and string body", () => { 26 | const options = { 27 | method: "POST", 28 | url: "https://example.com", 29 | headers: { "Content-Type": "application/json" }, 30 | query: { key: "value" }, 31 | body: JSON.stringify({ data: "test" }), 32 | }; 33 | const result = generatePHPRequestsCode(options); 34 | expect(result).toContain(`$method = 'POST';`); 35 | expect(result).toContain(`$url = 'https://example.com';`); 36 | expect(result).toContain(`$headers = [ 37 | 'Content-Type' => 'application/json' 38 | ]`); 39 | expect(result).toContain(`$query = [ 40 | 'key' => 'value' 41 | ]`); 42 | expect(result).toContain(`$body = [ 43 | 'data' => 'test' 44 | ]`); 45 | }); 46 | 47 | test("should generate correct PHP code with POST method and JsonBody", () => { 48 | const options = { 49 | method: "POST", 50 | url: "https://example.com", 51 | headers: { "Content-Type": "application/json" }, 52 | query: { key: "value" }, 53 | body: new JsonBody({ data: "test", nested: { key: "value" } }), 54 | }; 55 | const result = generatePHPRequestsCode(options); 56 | expect(result).toContain(`$method = 'POST';`); 57 | expect(result).toContain(`$url = 'https://example.com';`); 58 | expect(result).toContain(`$headers = [ 59 | 'Content-Type' => 'application/json' 60 | ]`); 61 | expect(result).toContain(`$query = [ 62 | 'key' => 'value' 63 | ]`); 64 | expect(result).toContain(`$body = [ 65 | 'data' => 'test', 66 | 'nested' => {"key":"value"} 67 | ]`); 68 | }); 69 | 70 | test("should generate correct PHP code with non-JSON string body", () => { 71 | const options = { 72 | method: "POST", 73 | url: "https://example.com", 74 | headers: { "Content-Type": "text/plain" }, 75 | body: "Hello, world!", 76 | }; 77 | const result = generatePHPRequestsCode(options); 78 | expect(result).toContain(`$method = 'POST';`); 79 | expect(result).toContain(`$url = 'https://example.com';`); 80 | expect(result).toContain(`$headers = [ 81 | 'Content-Type' => 'text/plain' 82 | ]`); 83 | expect(result).toContain(`$body = 'Hello, world!';`); 84 | }); 85 | 86 | test("should handle empty objects properly", () => { 87 | const options = { 88 | method: "GET", 89 | url: "https://example.com", 90 | headers: {}, 91 | query: {}, 92 | }; 93 | const result = generatePHPRequestsCode(options); 94 | expect(result).toContain(`$headers = [];`); 95 | expect(result).toContain(`$query = [];`); 96 | expect(result).toContain(`$body = [];`); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /src/generators/php-requests.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptions, JsonBody } from "../request"; 2 | 3 | export function generatePHPRequestsCode(options: RequestOptions): string { 4 | const formatObject = (obj: any): string => { 5 | if (!obj || Object.keys(obj).length === 0) { 6 | return '[]'; 7 | } 8 | const entries = Object.entries(obj).map(([key, value]) => 9 | ` '${key}' => ${typeof value === 'string' ? `'${value}'` : JSON.stringify(value)}` 10 | ).join(",\n"); 11 | return `[\n${entries}\n]`; 12 | }; 13 | 14 | let code = `status_code >= 400) {\n`; 38 | code += ` throw new Exception('Server responded with status code ' . $response->status_code);\n`; 39 | code += `}\n`; 40 | code += `?>` 41 | return code; 42 | } 43 | -------------------------------------------------------------------------------- /src/generators/php.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generatePHPCode } from "./php"; 3 | import { JsonBody } from "../request"; 4 | 5 | describe('generatePHPCode', () => { 6 | test('should generate PHP code with default method when no method is provided', () => { 7 | const options = { url: 'http://example.com' }; 8 | const result = generatePHPCode(options); 9 | expect(result).toContain(`$method = 'GET';`); 10 | expect(result).toContain(`$url = 'http://example.com';`); 11 | }); 12 | 13 | test('should generate PHP code with provided method', () => { 14 | const options = { method: 'POST', url: 'http://example.com' }; 15 | const result = generatePHPCode(options); 16 | expect(result).toContain(`$method = 'POST';`); 17 | }); 18 | 19 | test('should generate PHP code with query parameters on separate lines', () => { 20 | const options = { 21 | url: 'http://example.com', 22 | query: { 23 | param1: 'value1', 24 | param2: ['value2', 'value3'] 25 | } 26 | }; 27 | const result = generatePHPCode(options); 28 | expect(result).toContain(`$query = [`); 29 | expect(result).toContain(` 'param1' => "value1",`); 30 | expect(result).toContain(` 'param2' => ["value2","value3"],`); 31 | expect(result).toContain(`$url .= '?' . http_build_query($query);`); 32 | }); 33 | 34 | test('should generate PHP code with headers on separate lines', () => { 35 | const options = { 36 | url: 'http://example.com', 37 | headers: { 38 | 'Content-Type': 'application/json', 39 | 'Authorization': 'Bearer token' 40 | } 41 | }; 42 | const result = generatePHPCode(options); 43 | expect(result).toContain(` 'header' => [`); 44 | expect(result).toContain(` 'Content-Type: application/json',`); 45 | expect(result).toContain(` 'Authorization: Bearer token',`); 46 | }); 47 | 48 | test('should format JSON body properly', () => { 49 | const options = { 50 | url: 'http://example.com', 51 | body: new JsonBody({ 52 | key1: 'value1', 53 | key2: { 54 | nested: 'value2' 55 | }, 56 | key3: ['item1', 'item2'] 57 | }) 58 | }; 59 | const result = generatePHPCode(options); 60 | expect(result).toContain(` 'content' => json_encode([`); 61 | expect(result).toContain(` 'key1' => "value1",`); 62 | expect(result).toContain(` 'key2' => {"nested":"value2"},`); 63 | expect(result).toContain(` 'key3' => ["item1","item2"],`); 64 | expect(result).toContain(` ]),`); 65 | }); 66 | 67 | test('should handle string body content', () => { 68 | const options = { 69 | url: 'http://example.com', 70 | body: 'plain text content' 71 | }; 72 | const result = generatePHPCode(options); 73 | expect(result).toContain(` 'content' => 'plain text content',`); 74 | }); 75 | 76 | test('response variable should be the last one', () => { 77 | const options = { url: 'http://example.com' }; 78 | const result = generatePHPCode(options); 79 | expect(result).toMatch(/\$response = [^;]+;$/); 80 | }); 81 | }); -------------------------------------------------------------------------------- /src/generators/php.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptions, JsonBody } from "../request"; 2 | 3 | export function generatePHPCode(options: RequestOptions): string { 4 | let code = ` ${JSON.stringify(value)},\n`; 13 | } 14 | code += `];\n`; 15 | code += `$url .= '?' . http_build_query($query);\n`; 16 | } 17 | 18 | code += `\n$options = [\n`; 19 | code += ` 'http' => [\n`; 20 | code += ` 'method' => $method,\n`; 21 | 22 | if (options.headers) { 23 | code += ` 'header' => [\n`; 24 | for (const [key, value] of Object.entries(options.headers)) { 25 | code += ` '${key}: ${value}',\n`; 26 | } 27 | code += ` ],\n`; 28 | } 29 | 30 | if (options.body) { 31 | if (options.body instanceof JsonBody) { 32 | code += ` 'content' => json_encode([\n`; 33 | for (const [key, value] of Object.entries(options.body.body)) { 34 | code += ` '${key}' => ${JSON.stringify(value)},\n`; 35 | } 36 | code += ` ]),\n`; 37 | } else { 38 | code += ` 'content' => '${options.body}',\n`; 39 | } 40 | } 41 | 42 | code += ` ],\n`; 43 | code += `];\n\n`; 44 | 45 | code += `$context = stream_context_create($options); 46 | $response = file_get_contents($url, false, $context);`; 47 | 48 | return code; 49 | } -------------------------------------------------------------------------------- /src/generators/python-requests.test.ts: -------------------------------------------------------------------------------- 1 | import { JsonBody, RequestOptions } from "../request"; 2 | import { describe, expect, test } from "@jest/globals"; 3 | import { generatePythonRequestsCode } from "./python-requests"; 4 | 5 | describe("generatePythonRequestsCode", () => { 6 | test("should generate code with default method and no params, headers or data", () => { 7 | const options = { url: "http://example.com" }; 8 | const expected = 9 | "import requests\n\n" + 10 | "def call_api():\n" + 11 | ' url = "http://example.com"\n' + 12 | " params = None\n" + 13 | ' method = "GET"\n' + 14 | " headers = None\n" + 15 | " data = None\n" + 16 | " response = requests.request(method, url, headers=headers, params=params, json=data if isinstance(data, dict) else data)\n"; 17 | expect(generatePythonRequestsCode(options)).toBe(expected); 18 | }); 19 | 20 | test("should generate code with provided method, params, headers and JSON body", () => { 21 | const jsonBody = new JsonBody({ key: "value" }); 22 | const options = { 23 | url: "http://example.com", 24 | query: { key: "value" }, 25 | method: "POST", 26 | headers: { "Content-Type": "application/json" }, 27 | body: jsonBody, 28 | }; 29 | const expected = 30 | "import requests\n\n" + 31 | "def call_api():\n" + 32 | ' url = "http://example.com"\n' + 33 | " params = {\n" + 34 | ' "key": "value",\n' + 35 | " }\n" + 36 | ' method = "POST"\n' + 37 | " headers = {\n" + 38 | ' "Content-Type": "application/json",\n' + 39 | " }\n" + 40 | " data = {\n" + 41 | ' "key": "value",\n' + 42 | " }\n" + 43 | " response = requests.request(method, url, headers=headers, params=params, json=data if isinstance(data, dict) else data)\n"; 44 | expect(generatePythonRequestsCode(options)).toBe(expected); 45 | }); 46 | 47 | test("should generate code with provided method and no params, headers or data", () => { 48 | const options = { url: "http://example.com", method: "DELETE" }; 49 | const expected = 50 | "import requests\n\n" + 51 | "def call_api():\n" + 52 | ' url = "http://example.com"\n' + 53 | " params = None\n" + 54 | ' method = "DELETE"\n' + 55 | " headers = None\n" + 56 | " data = None\n" + 57 | " response = requests.request(method, url, headers=headers, params=params, json=data if isinstance(data, dict) else data)\n"; 58 | expect(generatePythonRequestsCode(options)).toBe(expected); 59 | }); 60 | 61 | test("should generate code with provided params and no method, headers or data", () => { 62 | const options = { url: "http://example.com", query: { key: "value" } }; 63 | const expected = 64 | "import requests\n\n" + 65 | "def call_api():\n" + 66 | ' url = "http://example.com"\n' + 67 | " params = {\n" + 68 | ' "key": "value",\n' + 69 | " }\n" + 70 | ' method = "GET"\n' + 71 | " headers = None\n" + 72 | " data = None\n" + 73 | " response = requests.request(method, url, headers=headers, params=params, json=data if isinstance(data, dict) else data)\n"; 74 | expect(generatePythonRequestsCode(options)).toBe(expected); 75 | }); 76 | 77 | test("should generate code with provided headers and no method, params or data", () => { 78 | const options = { 79 | url: "http://example.com", 80 | headers: { "Content-Type": "application/json" }, 81 | }; 82 | const expected = 83 | "import requests\n\n" + 84 | "def call_api():\n" + 85 | ' url = "http://example.com"\n' + 86 | " params = None\n" + 87 | ' method = "GET"\n' + 88 | " headers = {\n" + 89 | ' "Content-Type": "application/json",\n' + 90 | " }\n" + 91 | " data = None\n" + 92 | " response = requests.request(method, url, headers=headers, params=params, json=data if isinstance(data, dict) else data)\n"; 93 | expect(generatePythonRequestsCode(options)).toBe(expected); 94 | }); 95 | 96 | test("should generate code with raw string body", () => { 97 | const options = { 98 | url: "http://example.com", 99 | method: "POST", 100 | body: "raw string data", 101 | }; 102 | const expected = 103 | "import requests\n\n" + 104 | "def call_api():\n" + 105 | ' url = "http://example.com"\n' + 106 | " params = None\n" + 107 | ' method = "POST"\n' + 108 | " headers = None\n" + 109 | " data = 'raw string data'\n" + 110 | " response = requests.request(method, url, headers=headers, params=params, json=data if isinstance(data, dict) else data)\n"; 111 | expect(generatePythonRequestsCode(options)).toBe(expected); 112 | }); 113 | }); 114 | -------------------------------------------------------------------------------- /src/generators/python-requests.ts: -------------------------------------------------------------------------------- 1 | import { JsonBody, RequestOptions } from "../request"; 2 | 3 | export function generatePythonRequestsCode(options: RequestOptions): string { 4 | let code = `import requests\n\n`; 5 | code += `def call_api():\n`; 6 | code += ` url = "${options.url}"\n`; 7 | 8 | if (options.query) { 9 | code += ` params = {\n`; 10 | Object.entries(options.query).forEach(([key, value]) => { 11 | code += ` "${key}": ${JSON.stringify(value)},\n`; 12 | }); 13 | code += ` }\n`; 14 | } else { 15 | code += ` params = None\n`; 16 | } 17 | 18 | if (options.method) { 19 | code += ` method = "${options.method}"\n`; 20 | } else { 21 | code += ` method = "GET"\n`; 22 | } 23 | 24 | if (options.headers) { 25 | code += ` headers = {\n`; 26 | Object.entries(options.headers).forEach(([key, value]) => { 27 | code += ` "${key}": "${value}",\n`; 28 | }); 29 | code += ` }\n`; 30 | } else { 31 | code += ` headers = None\n`; 32 | } 33 | 34 | if (options.body) { 35 | if (options.body instanceof JsonBody) { 36 | code += ` data = {\n`; 37 | Object.entries(options.body.body).forEach(([key, value]) => { 38 | code += ` "${key}": ${JSON.stringify(value)},\n`; 39 | }); 40 | code += ` }\n`; 41 | } else { 42 | code += ` data = '${options.body}'\n`; 43 | } 44 | } else { 45 | code += ` data = None\n`; 46 | } 47 | 48 | code += ` response = requests.request(method, url, headers=headers, params=params, json=data if isinstance(data, dict) else data)\n`; 49 | 50 | return code; 51 | } 52 | -------------------------------------------------------------------------------- /src/generators/python.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generatePythonCode } from "./python"; 3 | import { JsonBody } from "../request"; 4 | 5 | describe("generatePythonCode", () => { 6 | test("should generate correct code when all options are provided", () => { 7 | const options = { 8 | url: "http://example.com", 9 | query: { key: "value" }, 10 | method: "POST", 11 | headers: { "Content-Type": "application/json" }, 12 | body: new JsonBody({ key: "value" }), 13 | }; 14 | 15 | const result = generatePythonCode(options); 16 | expect(result).toContain("from urllib.parse import urlencode"); 17 | expect(result).toContain("from urllib.request import Request, urlopen"); 18 | expect(result).toContain("from urllib.error import HTTPError"); 19 | expect(result).toContain("import json"); 20 | expect(result).toContain("import ssl"); 21 | expect(result).toContain("def call_api():"); 22 | expect(result).toContain('url = "http://example.com"'); 23 | expect(result).toContain("request = Request(url)"); 24 | expect(result).toContain('request.method = "POST"'); 25 | expect(result).toContain( 26 | 'request.add_header("Content-Type", "application/json")' 27 | ); 28 | expect(result).toContain("data = {"); 29 | expect(result).toContain('"key": "value"'); 30 | expect(result).toContain("request.data = json.dumps(data).encode()"); 31 | expect(result).toContain("ctx = ssl.create_default_context()"); 32 | expect(result).toContain("response = urlopen(request, context=ctx)"); 33 | }); 34 | 35 | test("should generate correct code when only url is provided", () => { 36 | const options = { url: "http://example.com" }; 37 | 38 | const result = generatePythonCode(options); 39 | expect(result).toContain("from urllib.parse import urlencode"); 40 | expect(result).toContain("from urllib.request import Request, urlopen"); 41 | expect(result).toContain("from urllib.error import HTTPError"); 42 | expect(result).toContain("import json"); 43 | expect(result).toContain("import ssl"); 44 | expect(result).toContain("def call_api():"); 45 | expect(result).toContain('url = "http://example.com"'); 46 | expect(result).toContain("request = Request(url)"); 47 | expect(result).toContain('request.method = "GET"'); 48 | expect(result).toContain("ctx = ssl.create_default_context()"); 49 | expect(result).toContain("response = urlopen(request, context=ctx)"); 50 | }); 51 | 52 | test("should generate correct code when method is not provided", () => { 53 | const options = { url: "http://example.com", query: { key: "value" } }; 54 | 55 | const result = generatePythonCode(options); 56 | expect(result).toContain("from urllib.parse import urlencode"); 57 | expect(result).toContain("from urllib.request import Request, urlopen"); 58 | expect(result).toContain("from urllib.error import HTTPError"); 59 | expect(result).toContain("import json"); 60 | expect(result).toContain("import ssl"); 61 | expect(result).toContain("def call_api():"); 62 | expect(result).toContain('url = "http://example.com"'); 63 | expect(result).toContain("request = Request(url)"); 64 | expect(result).toContain('request.method = "GET"'); 65 | expect(result).toContain("ctx = ssl.create_default_context()"); 66 | expect(result).toContain("response = urlopen(request, context=ctx)"); 67 | }); 68 | 69 | test("should generate correct code when headers are not provided", () => { 70 | const options = { 71 | url: "http://example.com", 72 | method: "POST", 73 | body: new JsonBody({ key: "value" }), 74 | }; 75 | 76 | const result = generatePythonCode(options); 77 | 78 | console.log(result); 79 | 80 | expect(result).toContain("from urllib.parse import urlencode"); 81 | expect(result).toContain("from urllib.request import Request, urlopen"); 82 | expect(result).toContain("from urllib.error import HTTPError"); 83 | expect(result).toContain("import json"); 84 | expect(result).toContain("import ssl"); 85 | expect(result).toContain("def call_api():"); 86 | expect(result).toContain('url = "http://example.com"'); 87 | expect(result).toContain("request = Request(url)"); 88 | expect(result).toContain('request.method = "POST"'); 89 | expect(result).toContain("data = {"); 90 | expect(result).toContain('"key": "value"'); 91 | expect(result).toContain("request.data = json.dumps(data).encode()"); 92 | expect(result).toContain("ctx = ssl.create_default_context()"); 93 | expect(result).toContain("response = urlopen(request, context=ctx)"); 94 | }); 95 | 96 | test("should generate correct code when body is not provided", () => { 97 | const options = { 98 | url: "http://example.com", 99 | method: "POST", 100 | headers: { "Content-Type": "application/json" }, 101 | }; 102 | 103 | const result = generatePythonCode(options); 104 | expect(result).toContain("from urllib.parse import urlencode"); 105 | expect(result).toContain("from urllib.request import Request, urlopen"); 106 | expect(result).toContain("from urllib.error import HTTPError"); 107 | expect(result).toContain("import json"); 108 | expect(result).toContain("import ssl"); 109 | expect(result).toContain("def call_api():"); 110 | expect(result).toContain('url = "http://example.com"'); 111 | expect(result).toContain("request = Request(url)"); 112 | expect(result).toContain('request.method = "POST"'); 113 | expect(result).toContain( 114 | 'request.add_header("Content-Type", "application/json")' 115 | ); 116 | expect(result).toContain("ctx = ssl.create_default_context()"); 117 | expect(result).toContain("response = urlopen(request, context=ctx)"); 118 | }); 119 | }); 120 | -------------------------------------------------------------------------------- /src/generators/python.ts: -------------------------------------------------------------------------------- 1 | import { JsonBody, RequestOptions } from "../request"; 2 | 3 | export function generatePythonCode(options: RequestOptions): string { 4 | let code = `from urllib.parse import urlencode 5 | from urllib.request import Request, urlopen 6 | from urllib.error import HTTPError 7 | import json 8 | import ssl 9 | 10 | def call_api(): 11 | url = "${options.url}"\n`; 12 | 13 | if (options.query) { 14 | code += ` query_params = {\n`; 15 | Object.entries(options.query).forEach(([key, value]) => { 16 | if (Array.isArray(value)) { 17 | code += ` "${key}": ${JSON.stringify(value)},\n`; 18 | } else { 19 | code += ` "${key}": "${value}",\n`; 20 | } 21 | }); 22 | code += ` }\n`; 23 | code += ` url = f"{url}?{urlencode(query_params)}"\n`; 24 | } 25 | 26 | code += ` request = Request(url)\n`; 27 | code += ` request.method = "${options.method || "GET"}"\n`; 28 | 29 | if (options.headers) { 30 | Object.entries(options.headers).forEach(([key, value]) => { 31 | code += ` request.add_header("${key}", "${value}")\n`; 32 | }); 33 | } 34 | 35 | if (options.body) { 36 | let bodyData; 37 | if (options.body instanceof JsonBody) { 38 | bodyData = options.body.body; 39 | if (typeof bodyData === "object" && bodyData !== null) { 40 | code += ` data = {\n`; 41 | Object.entries(bodyData).forEach(([key, value]) => { 42 | if (typeof value === "object" && value !== null) { 43 | code += ` "${key}": ${JSON.stringify( 44 | value, 45 | null, 46 | 8 47 | ).replace(/\n/g, "\n ")},\n`; 48 | } else { 49 | code += ` "${key}": ${JSON.stringify(value)},\n`; 50 | } 51 | }); 52 | code += ` }\n`; 53 | code += ` request.data = json.dumps(data).encode()\n`; 54 | } else { 55 | code += ` request.data = '${options.body}'.encode()\n`; 56 | } 57 | } else { 58 | code += ` request.data = '${options.body}'.encode()\n`; 59 | } 60 | } 61 | 62 | code += ` ctx = ssl.create_default_context() 63 | try: 64 | response = urlopen(request, context=ctx) 65 | except HTTPError as e: 66 | response = e 67 | if response.code >= 400: 68 | raise 69 | return response\n`; 70 | 71 | return code; 72 | } 73 | -------------------------------------------------------------------------------- /src/generators/ruby.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateRubyCode } from "./ruby"; 3 | import { JsonBody } from "../request"; 4 | 5 | describe('generateRubyCode', () => { 6 | test('should generate basic code with only url', () => { 7 | const options = { url: 'http://example.com' }; 8 | const result = generateRubyCode(options); 9 | expect(result).toContain(`uri = URI.parse("http://example.com")`); 10 | }); 11 | 12 | test('should generate code with query parameters', () => { 13 | const options = { url: 'http://example.com', query: { param1: 'value1', param2: 'value2' } }; 14 | const result = generateRubyCode(options); 15 | expect(result).toContain(` query_params = { 16 | "param1" => value1, 17 | "param2" => value2 18 | }`); 19 | expect(result).toContain(`uri.query = URI.encode_www_form(query_params)`); 20 | }); 21 | 22 | test('should generate code with headers', () => { 23 | const options = { url: 'http://example.com', headers: { 'Content-Type': 'application/json' } }; 24 | const result = generateRubyCode(options); 25 | expect(result).toContain(` request.initialize_http_header( 26 | "Content-Type" => "application/json" 27 | )`); 28 | }); 29 | 30 | test('should generate code with body', () => { 31 | const options = { 32 | url: 'http://example.com', 33 | body: new JsonBody({ key1: 'value1', key2: 'value2' }) 34 | }; 35 | const result = generateRubyCode(options); 36 | expect(result).toContain(` body = { 37 | "key1" => "value1", 38 | "key2" => "value2" 39 | }`); 40 | expect(result).toContain(`request.body = body.to_json`); 41 | }); 42 | 43 | test('should generate code with string body', () => { 44 | const options = { url: 'http://example.com', body: 'body content' }; 45 | const result = generateRubyCode(options); 46 | expect(result).toContain(`request.body = 'body content'`); 47 | }); 48 | 49 | test('should generate code with custom HTTP method', () => { 50 | const options = { url: 'http://example.com', method: 'Post' }; 51 | const result = generateRubyCode(options); 52 | expect(result).toContain(`request = Net::HTTP::Post.new(uri.request_uri)`); 53 | }); 54 | }); -------------------------------------------------------------------------------- /src/generators/ruby.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptions, JsonBody } from "../request"; 2 | 3 | export function generateRubyCode(options: RequestOptions): string { 4 | let code = `require 'net/http' 5 | require 'uri' 6 | require 'json' 7 | 8 | def send_request 9 | uri = URI.parse("${options.url}") 10 | `; 11 | 12 | if (options.query) { 13 | code += ` query_params = {\n`; 14 | Object.entries(options.query).forEach(([key, value], index, array) => { 15 | code += ` "${key}" => ${value}${index < array.length - 1 ? ',' : ''}\n`; 16 | }); 17 | code += ` }\n`; 18 | code += ` uri.query = URI.encode_www_form(query_params)\n\n`; 19 | } 20 | 21 | code += ` http = Net::HTTP.new(uri.host, uri.port) 22 | http.use_ssl = uri.scheme == 'https'\n\n`; 23 | 24 | const method = options.method || "GET"; 25 | const methodFormatted = method.charAt(0).toUpperCase() + method.slice(1).toLowerCase(); 26 | code += ` request = Net::HTTP::${methodFormatted}.new(uri.request_uri)\n`; 27 | 28 | if (options.headers) { 29 | code += `\n request.initialize_http_header(\n`; 30 | Object.entries(options.headers).forEach(([key, value], index, array) => { 31 | code += ` "${key}" => "${value}"${index < array.length - 1 ? ',' : ''}\n`; 32 | }); 33 | code += ` )\n`; 34 | } 35 | 36 | if (options.body) { 37 | code += `\n`; 38 | if (options.body instanceof JsonBody) { 39 | code += ` body = {\n`; 40 | Object.entries(options.body.body).forEach(([key, value], index, array) => { 41 | code += ` "${key}" => ${JSON.stringify(value)}${index < array.length - 1 ? ',' : ''}\n`; 42 | }); 43 | code += ` }\n`; 44 | code += ` request.body = body.to_json\n`; 45 | } else { 46 | code += ` request.body = '${options.body}'\n`; 47 | } 48 | } 49 | 50 | code += `\n begin 51 | response = http.request(request) 52 | case response 53 | when Net::HTTPSuccess 54 | response 55 | else 56 | raise "HTTP Error: #{response.code} - #{response.message}" 57 | end 58 | rescue StandardError => e 59 | raise "Request failed: #{e.message}" 60 | end 61 | end 62 | 63 | send_request if __FILE__ == $PROGRAM_NAME\n`; 64 | 65 | return code; 66 | } 67 | -------------------------------------------------------------------------------- /src/generators/rust.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateRustCode } from "./rust"; 3 | import { JsonBody } from "../request"; 4 | 5 | describe('generateRustCode', () => { 6 | test('should generate code with GET method by default', () => { 7 | const options = { url: 'http://example.com' }; 8 | const result = generateRustCode(options); 9 | expect(result).toContain('Method::GET'); 10 | }); 11 | 12 | test('should generate code with provided method', () => { 13 | const options = { url: 'http://example.com', method: 'POST' }; 14 | const result = generateRustCode(options); 15 | expect(result).toContain('Method::POST'); 16 | }); 17 | 18 | test('should generate code with query parameters', () => { 19 | const options = { url: 'http://example.com', query: { foo: 'bar', baz: ['qux', 'quux'] } }; 20 | const result = generateRustCode(options); 21 | expect(result).toContain('let query_params: Value = serde_json::json!('); 22 | expect(result).toContain('"foo": "bar"'); 23 | expect(result).toContain('"baz": ['); 24 | expect(result).toContain('Value::Array(arr) =>'); 25 | }); 26 | 27 | test('should generate code with headers', () => { 28 | const options = { url: 'http://example.com', headers: { 'Content-Type': 'application/json' } }; 29 | const result = generateRustCode(options); 30 | expect(result).toContain('.headers('); 31 | expect(result).toContain('"Content-Type": "application/json"'); 32 | expect(result).toContain('.into())'); 33 | }); 34 | 35 | test('should generate code with body', () => { 36 | const options = { url: 'http://example.com', body: 'Hello, world!' }; 37 | const result = generateRustCode(options); 38 | expect(result).toContain('.body("Hello, world!")'); 39 | }); 40 | 41 | test('should generate code with JSON body', () => { 42 | const options = { 43 | url: 'http://example.com', 44 | body: new JsonBody({ 45 | name: 'John', 46 | age: 30 47 | }) 48 | }; 49 | const result = generateRustCode(options); 50 | expect(result).toContain('.json(&serde_json::json!('); 51 | expect(result).toContain('"name": "John"'); 52 | expect(result).toContain('"age": 30'); 53 | }); 54 | }); -------------------------------------------------------------------------------- /src/generators/rust.ts: -------------------------------------------------------------------------------- 1 | import { RequestOptions } from "../request"; 2 | 3 | export function generateRustCode(options: RequestOptions): string { 4 | let code = `use reqwest::{Client, Method}; 5 | use serde_json::Value; 6 | 7 | pub async fn make_request() -> Result { 8 | let client = Client::new(); 9 | let mut url = "${options.url}".parse()?;`; 10 | 11 | if (options.query) { 12 | const queryStr = JSON.stringify(options.query, null, 4) 13 | .split('\n') 14 | .map(line => ' ' + line) 15 | .join('\n'); 16 | 17 | code += ` 18 | let query_params: Value = serde_json::json!( 19 | ${queryStr} 20 | ); 21 | if let Value::Object(params) = query_params { 22 | let query_string = params.iter() 23 | .flat_map(|(k, v)| match v { 24 | Value::Array(arr) => arr.iter() 25 | .map(|x| (k.clone(), x.to_string())) 26 | .collect::>(), 27 | _ => vec![(k.clone(), v.to_string())] 28 | }) 29 | .collect::>(); 30 | url.query_pairs_mut().extend_pairs(query_string); 31 | }`; 32 | } 33 | 34 | code += ` 35 | let request = client.request(Method::${options.method || 'GET'}, url)`; 36 | 37 | if (options.headers) { 38 | const headersStr = JSON.stringify(options.headers, null, 4) 39 | .split('\n') 40 | .map(line => ' ' + line) 41 | .join('\n'); 42 | 43 | code += ` 44 | .headers( 45 | ${headersStr} 46 | .into())`; 47 | } 48 | 49 | if (options.body) { 50 | if (typeof options.body === 'string') { 51 | try { 52 | const parsedBody = JSON.parse(options.body); 53 | const bodyStr = JSON.stringify(parsedBody, null, 4) 54 | .split('\n') 55 | .map(line => ' ' + line) 56 | .join('\n'); 57 | 58 | code += ` 59 | .json(&serde_json::json!( 60 | ${bodyStr} 61 | ))`; 62 | } catch { 63 | code += ` 64 | .body("${options.body}")`; 65 | } 66 | } else { 67 | const bodyStr = JSON.stringify(options.body, null, 4) 68 | .split('\n') 69 | .map(line => ' ' + line) 70 | .join('\n'); 71 | 72 | code += ` 73 | .json(&serde_json::json!( 74 | ${bodyStr} 75 | ))`; 76 | } 77 | } 78 | 79 | code += ` 80 | .send() 81 | .await?; 82 | Ok(response) 83 | }`; 84 | 85 | return code; 86 | } 87 | 88 | -------------------------------------------------------------------------------- /src/generators/swift.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateSwiftCode } from "./swift"; 3 | 4 | describe('generateSwiftCode', () => { 5 | test('should generate code with only url', () => { 6 | const options = { url: 'https://example.com' }; 7 | const result = generateSwiftCode(options); 8 | expect(result).toContain('import Foundation'); 9 | expect(result).toContain('var request = URLRequest(url: URL(string: "https://example.com")!,timeoutInterval: Double.infinity)'); 10 | expect(result).toContain('let task = URLSession.shared.dataTask(with: request)'); 11 | }); 12 | 13 | test('should generate code with url and method', () => { 14 | const options = { url: 'https://example.com', method: 'POST' }; 15 | const result = generateSwiftCode(options); 16 | expect(result).toContain('request.httpMethod = "POST"'); 17 | }); 18 | 19 | test('should generate code with url, method and headers', () => { 20 | const options = { url: 'https://example.com', method: 'POST', headers: { 'Content-Type': 'application/json' } }; 21 | const result = generateSwiftCode(options); 22 | expect(result).toContain('request.addValue("application/json", forHTTPHeaderField: "Content-Type")'); 23 | }); 24 | 25 | test('should generate code with url, method, headers and body', () => { 26 | const options = { url: 'https://example.com', method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{"key":"value"}' }; 27 | const result = generateSwiftCode(options); 28 | expect(result).toContain('request.httpBody = "{"key":"value"}".data(using: .utf8)'); 29 | }); 30 | 31 | test('should generate code with url, method, headers, body and query', () => { 32 | const options = { url: 'https://example.com', method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{"key":"value"}', query: { 'param': 'value' } }; 33 | const result = generateSwiftCode(options); 34 | expect(result).toContain('URLQueryItem(name: "param", value: "value")'); 35 | }); 36 | }); -------------------------------------------------------------------------------- /src/generators/swift.ts: -------------------------------------------------------------------------------- 1 | import { JsonBody, RequestOptions } from "../request"; 2 | 3 | export function generateSwiftCode(options: RequestOptions): string { 4 | let code = `import Foundation\n\n`; 5 | 6 | // Build URL components first 7 | if (options.query) { 8 | code += `let components = URLComponents(string: "${options.url}")!\n`; 9 | code += `let queryItems: [URLQueryItem] = [\n`; 10 | code += Object.entries(options.query).map(([key, value]) => { 11 | if (Array.isArray(value)) { 12 | return value.map(v => ` URLQueryItem(name: "${key}", value: "${v}")`) 13 | .join(",\n"); 14 | } 15 | return ` URLQueryItem(name: "${key}", value: "${value}")`; 16 | }).join(",\n"); 17 | code += `\n]\n`; 18 | code += `components.queryItems = queryItems\n\n`; 19 | code += `var request = URLRequest(url: components.url!,timeoutInterval: Double.infinity)\n`; 20 | } else { 21 | code += `var request = URLRequest(url: URL(string: "${options.url}")!,timeoutInterval: Double.infinity)\n`; 22 | } 23 | 24 | if (options.method) { 25 | code += `request.httpMethod = "${options.method}"\n`; 26 | } 27 | 28 | if (options.headers) { 29 | const headers = Object.entries(options.headers) 30 | .map(([key, value]) => `request.addValue("${value}", forHTTPHeaderField: "${key}")`) 31 | .join("\n"); 32 | code += headers + "\n"; 33 | } 34 | 35 | if (options.body) { 36 | if (options.body instanceof JsonBody) { 37 | code += `let parameters: [String: Any] = ${JSON.stringify(options.body.body, null, 4)}\n`; 38 | code += `request.httpBody = try? JSONSerialization.data(withJSONObject: parameters)\n`; 39 | code += `request.addValue("application/json", forHTTPHeaderField: "Content-Type")\n`; 40 | } else { 41 | code += `request.httpBody = "${options.body}".data(using: .utf8)\n`; 42 | } 43 | } 44 | 45 | code += `\nlet task = URLSession.shared.dataTask(with: request) { data, response, error in\n`; 46 | code += ` if let error = error {\n`; 47 | code += ` print("Error: \\(error)")\n`; 48 | code += ` return\n`; 49 | code += ` }\n`; 50 | code += ` let response = data\n`; 51 | code += `}\n`; 52 | code += `task.resume()\n`; 53 | 54 | return code; 55 | } 56 | -------------------------------------------------------------------------------- /src/generators/wget.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "@jest/globals"; 2 | import { generateWgetCode } from "./wget"; 3 | 4 | describe('generateWgetCode', () => { 5 | test('should generate wget command for GET method', () => { 6 | const options = { 7 | method: 'GET', 8 | url: 'http://example.com', 9 | }; 10 | const result = generateWgetCode(options); 11 | expect(result).toBe('wget \\\n \'http://example.com\''); 12 | }); 13 | 14 | test('should generate wget command for POST method', () => { 15 | const options = { 16 | method: 'POST', 17 | body: 'testBody', 18 | url: 'http://example.com', 19 | }; 20 | const result = generateWgetCode(options); 21 | expect(result).toBe('wget --post-data \'testBody\' \\\n \'http://example.com\''); 22 | }); 23 | 24 | test('should generate wget command with headers', () => { 25 | const options = { 26 | method: 'GET', 27 | headers: { 28 | 'Content-Type': 'application/json', 29 | 'Authorization': 'Bearer token', 30 | }, 31 | url: 'http://example.com', 32 | }; 33 | const result = generateWgetCode(options); 34 | expect(result).toBe('wget \\\n --header \'Content-Type: application/json\' \\\n --header \'Authorization: Bearer token\' \\\n \'http://example.com\''); 35 | }); 36 | 37 | test('should generate wget command with query parameters', () => { 38 | const options = { 39 | method: 'GET', 40 | query: { 41 | key1: 'value1', 42 | key2: 'value2', 43 | }, 44 | url: 'http://example.com', 45 | }; 46 | const result = generateWgetCode(options); 47 | expect(result).toBe('wget \\\n \'http://example.com?key1=value1&key2=value2\''); 48 | }); 49 | 50 | test('should generate wget command with all options', () => { 51 | const options = { 52 | method: 'POST', 53 | body: 'testBody', 54 | headers: { 55 | 'Content-Type': 'application/json', 56 | 'Authorization': 'Bearer token', 57 | }, 58 | query: { 59 | key1: 'value1', 60 | key2: 'value2', 61 | }, 62 | url: 'http://example.com', 63 | }; 64 | const result = generateWgetCode(options); 65 | expect(result).toBe('wget --post-data \'testBody\' \\\n --header \'Content-Type: application/json\' \\\n --header \'Authorization: Bearer token\' \\\n \'http://example.com?key1=value1&key2=value2\''); 66 | }); 67 | }); -------------------------------------------------------------------------------- /src/generators/wget.ts: -------------------------------------------------------------------------------- 1 | import { JsonBody, RequestOptions } from "../request"; 2 | 3 | export function generateWgetCode(options: RequestOptions): string { 4 | let wgetCommand = `wget`; 5 | 6 | if (options.method && options.method.toUpperCase() === "POST") { 7 | if (options.body instanceof JsonBody) { 8 | wgetCommand += ` --post-data '${JSON.stringify(options.body.body)}'`; 9 | } else if (options.body) { 10 | wgetCommand += ` --post-data '${options.body}'`; 11 | } 12 | } 13 | 14 | if (options.headers) { 15 | for (const [key, value] of Object.entries(options.headers)) { 16 | wgetCommand += ` \\\n --header '${key}: ${value}'`; 17 | } 18 | } 19 | 20 | let url = options.url; 21 | if (options.query) { 22 | const queryParams = []; 23 | for (const [key, value] of Object.entries(options.query)) { 24 | if (Array.isArray(value)) { 25 | value.forEach(v => { 26 | queryParams.push(`${encodeURIComponent(key)}=${encodeURIComponent(v)}`); 27 | }); 28 | } else { 29 | queryParams.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`); 30 | } 31 | } 32 | url += (url.includes("?") ? "&" : "?") + queryParams.join("&"); 33 | } 34 | 35 | wgetCommand += ` \\\n '${url}'`; 36 | 37 | return wgetCommand; 38 | } 39 | -------------------------------------------------------------------------------- /src/request.ts: -------------------------------------------------------------------------------- 1 | export class JsonBody { 2 | public body: object; 3 | 4 | constructor(body: object) { 5 | this.body = body; 6 | } 7 | } 8 | 9 | export interface RequestOptions { 10 | url: string; 11 | query?: Record; 12 | method?: string; 13 | headers?: Record; 14 | body?: string | JsonBody; 15 | } 16 | -------------------------------------------------------------------------------- /src/scripts/examples.ts: -------------------------------------------------------------------------------- 1 | import { writeFile } from "fs/promises"; 2 | import { CodeTarget } from "../target"; 3 | 4 | import { generateCode, JsonBody, RequestOptions } from "../generator"; 5 | 6 | async function main() { 7 | const [outputPath] = process.argv.slice(2); 8 | if (!outputPath) { 9 | throw new Error("Output path is required"); 10 | } 11 | 12 | const examples: Record = {}; 13 | 14 | const options: { post: RequestOptions; get: RequestOptions } = { 15 | post: { 16 | url: "http://example.com", 17 | method: "POST", 18 | headers: { 19 | "Content-Type": "application/json", 20 | }, 21 | body: new JsonBody({ name: "John Doe", baz: ["qux", "quix"] }), 22 | }, 23 | get: { 24 | url: "http://example.com", 25 | method: "GET", 26 | query: { 27 | baz: ["qux", "quix"], 28 | foo: "bar", 29 | }, 30 | }, 31 | }; 32 | for (const [target, readableName] of Object.entries(CodeTarget)) { 33 | const postCode = await generateCode( 34 | options.post, 35 | readableName as CodeTarget 36 | ); 37 | if (!postCode) { 38 | throw new Error(`Failed to generate POST code for ${target}`); 39 | } 40 | const getCode = await generateCode( 41 | options.get, 42 | readableName as CodeTarget 43 | ); 44 | if (!getCode) { 45 | throw new Error(`Failed to generate GET code for ${target}`); 46 | } 47 | 48 | examples[`${target}_post`] = postCode; 49 | examples[`${target}_get`] = getCode; 50 | } 51 | 52 | let markdownContent = "# Code Examples\n\n"; 53 | 54 | for (const [target, code] of Object.entries(examples)) { 55 | const isPost = target.endsWith("_post"); 56 | const isGet = target.endsWith("_get"); 57 | const baseTarget = 58 | isPost || isGet 59 | ? target.substring(0, target.lastIndexOf("_")) 60 | : target; 61 | const targetName = CodeTarget[baseTarget as keyof typeof CodeTarget]; 62 | const methodType = isPost ? " (POST)" : isGet ? " (GET)" : ""; 63 | 64 | markdownContent += `## ${targetName}${methodType}\n\n\`\`\`${baseTarget}\n${code}\n\`\`\`\n\n`; 65 | } 66 | 67 | await writeFile(outputPath, markdownContent); 68 | } 69 | 70 | main() 71 | .then() 72 | .catch((e) => { 73 | console.error(e); 74 | process.exit(1); 75 | }); 76 | -------------------------------------------------------------------------------- /src/target.ts: -------------------------------------------------------------------------------- 1 | export enum CodeTarget { 2 | Clojure = "Clojure", 3 | CSharp = "C#", 4 | Curl = "curl", 5 | Dart = "Dart", 6 | Elixir = "Elixir", 7 | Go = "Go", 8 | Java = "Java", 9 | JavaScript = "JavaScript", 10 | Kotlin = "Kotlin", 11 | NodeHTTP = "Node (HTTP)", 12 | NodeAxios = "Node (Axios)", 13 | NodeFetch = "Node (Fetch)", 14 | ObjectiveC = "Objective-C", 15 | PHP = "PHP", 16 | PHPGuzzle = "PHP (Guzzle)", 17 | PHPRequests = "PHP (Requests)", 18 | Python = "Python", 19 | PythonRequests = "Python (Requests)", 20 | Ruby = "Ruby", 21 | Rust = "Rust", 22 | Swift = "Swift", 23 | Wget = "Wget", 24 | } 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "es2021" 5 | ], 6 | "module": "commonjs", 7 | "target": "es2021", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "outDir": "dist", 13 | "declarationDir": "dist/@types", 14 | "declaration": true, 15 | }, 16 | "include": [ 17 | "src/**/*" 18 | ], 19 | "exclude": [ 20 | "node_modules", 21 | "dist" 22 | ] 23 | } --------------------------------------------------------------------------------