Skip to content

Commit

Permalink
Generate Crystal language code (#343)
Browse files Browse the repository at this point in the history
* Generate Crystal language code

* Generate Crystal language code

* Remove a blank line

* fix crystal tests

---------

Co-authored-by: Filipe Freire <livrofubia@gmail.com>
  • Loading branch information
yanecc and filfreire authored Jul 12, 2024
1 parent 893da8b commit b9e1d7b
Show file tree
Hide file tree
Showing 26 changed files with 280 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![version][npm-version]][npm-url] [![License][npm-license]][license-url]

> HTTP Request snippet generator for _many_ languages & tools including: `cURL`, `HTTPie`, `JavaScript`, `Node`, `C`, `Java`, `PHP`, `Objective-C`, `Swift`, `Python`, `Ruby`, `C#`, `Go`, `OCaml` and [more](https://github.com/Kong/httpsnippet/wiki/Targets)!
> HTTP Request snippet generator for _many_ languages & tools including: `cURL`, `HTTPie`, `JavaScript`, `Node`, `C`, `Java`, `PHP`, `Objective-C`, `Swift`, `Python`, `Ruby`, `C#`, `Go`, `OCaml`, `Crystal` and [more](https://github.com/Kong/httpsnippet/wiki/Targets)!
Relies on the popular [HAR](http://www.softwareishard.com/blog/har-12-spec/#request) format to import data and describe HTTP calls.

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"keywords": [
"api",
"clojure",
"crystal",
"csharp",
"curl",
"go",
Expand Down
14 changes: 14 additions & 0 deletions src/helpers/__snapshots__/utils.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ Array [
"key": "clojure",
"title": "Clojure",
},
Object {
"clients": Array [
Object {
"description": "Crystal HTTP client",
"key": "native",
"link": "https://crystal-lang.org/api/master/HTTP/Client.html",
"title": "http::client",
},
],
"default": "native",
"extname": ".cr",
"key": "crystal",
"title": "Crystal",
},
Object {
"clients": Array [
Object {
Expand Down
18 changes: 18 additions & 0 deletions src/targets/crystal/native/client.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import https from '../../../fixtures/requests/https.json';
import { runCustomFixtures } from '../../../fixtures/runCustomFixtures';
import { Request } from '../../../httpsnippet';

runCustomFixtures({
targetId: 'crystal',
clientId: 'native',
tests: [
{
it: 'should support the insecureSkipVerify option',
input: https as Request,
options: {
insecureSkipVerify: true,
},
expected: 'insecure-skip-verify.cr',
},
],
});
72 changes: 72 additions & 0 deletions src/targets/crystal/native/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* @description
* HTTP code snippet generator for native Crystal
*
* @author
* @18183883296
*
* for any questions or issues regarding the generated code snippet, please open an issue mentioning the author.
*/
import { CodeBuilder } from '../../../helpers/code-builder';
import { escapeForDoubleQuotes } from '../../../helpers/escape';
import { Client } from '../../targets';

export interface CrystalNativeOptions {
insecureSkipVerify?: boolean;
}

export const native: Client<CrystalNativeOptions> = {
info: {
key: 'native',
title: 'http::client',
link: 'https://crystal-lang.org/api/master/HTTP/Client.html',
description: 'Crystal HTTP client',
},
convert: ({ method: rawMethod, fullUrl, postData, allHeaders }, options = {}) => {
const { insecureSkipVerify = false } = options;

const { push, blank, join } = new CodeBuilder();

push('require "http/client"');

blank();

push(`url = "${fullUrl}"`);

const headers = Object.keys(allHeaders);
if (headers.length) {
push('headers = HTTP::Headers{');
headers.forEach(key => {
push(` "${key}" => "${escapeForDoubleQuotes(allHeaders[key])}"`);
});
push('}');
}

if (postData.text) {
push(`reqBody = ${JSON.stringify(postData.text)}`);
}

blank();

const method = rawMethod.toUpperCase();
const methods = ['GET', 'POST', 'HEAD', 'DELETE', 'PATCH', 'PUT', 'OPTIONS'];

const headersContext = headers.length ? ', headers: headers' : '';
const bodyContext = postData.text ? ', body: reqBody' : '';
const sslContext = insecureSkipVerify ? ', tls: OpenSSL::SSL::Context::Client.insecure' : '';

if (methods.includes(method)) {
push(
`response = HTTP::Client.${method.toLowerCase()} url${headersContext}${bodyContext}${sslContext}`,
);
} else {
push(
`response = HTTP::Client.exec "${method}", url${headersContext}${bodyContext}${sslContext}`,
);
}

push('puts response.body');

return join();
},
};
10 changes: 10 additions & 0 deletions src/targets/crystal/native/fixtures/application-form-encoded.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "http/client"

url = "http://mockbin.com/har"
headers = HTTP::Headers{
"content-type" => "application/x-www-form-urlencoded"
}
reqBody = "foo=bar&hello=world"

response = HTTP::Client.post url, headers: headers, body: reqBody
puts response.body
10 changes: 10 additions & 0 deletions src/targets/crystal/native/fixtures/application-json.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "http/client"

url = "http://mockbin.com/har"
headers = HTTP::Headers{
"content-type" => "application/json"
}
reqBody = "{\"number\":1,\"string\":\"f\\\"oo\",\"arr\":[1,2,3],\"nested\":{\"a\":\"b\"},\"arr_mix\":[1,\"a\",{\"arr_mix_nested\":{}}],\"boolean\":false}"

response = HTTP::Client.post url, headers: headers, body: reqBody
puts response.body
9 changes: 9 additions & 0 deletions src/targets/crystal/native/fixtures/cookies.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require "http/client"

url = "http://mockbin.com/har"
headers = HTTP::Headers{
"cookie" => "foo=bar; bar=baz"
}

response = HTTP::Client.post url, headers: headers
puts response.body
6 changes: 6 additions & 0 deletions src/targets/crystal/native/fixtures/custom-method.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require "http/client"

url = "http://mockbin.com/har"

response = HTTP::Client.exec "PROPFIND", url
puts response.body
12 changes: 12 additions & 0 deletions src/targets/crystal/native/fixtures/full.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
require "http/client"

url = "http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value"
headers = HTTP::Headers{
"cookie" => "foo=bar; bar=baz"
"accept" => "application/json"
"content-type" => "application/x-www-form-urlencoded"
}
reqBody = "foo=bar"

response = HTTP::Client.post url, headers: headers, body: reqBody
puts response.body
11 changes: 11 additions & 0 deletions src/targets/crystal/native/fixtures/headers.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require "http/client"

url = "http://mockbin.com/har"
headers = HTTP::Headers{
"accept" => "application/json"
"x-foo" => "Bar"
"quoted-value" => "\"quoted\" 'string'"
}

response = HTTP::Client.get url, headers: headers
puts response.body
6 changes: 6 additions & 0 deletions src/targets/crystal/native/fixtures/https.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require "http/client"

url = "https://mockbin.com/har"

response = HTTP::Client.get url
puts response.body
6 changes: 6 additions & 0 deletions src/targets/crystal/native/fixtures/insecure-skip-verify.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require "http/client"

url = "https://mockbin.com/har"

response = HTTP::Client.get url, tls: OpenSSL::SSL::Context::Client.insecure
puts response.body
10 changes: 10 additions & 0 deletions src/targets/crystal/native/fixtures/jsonObj-multiline.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "http/client"

url = "http://mockbin.com/har"
headers = HTTP::Headers{
"content-type" => "application/json"
}
reqBody = "{\n \"foo\": \"bar\"\n}"

response = HTTP::Client.post url, headers: headers, body: reqBody
puts response.body
10 changes: 10 additions & 0 deletions src/targets/crystal/native/fixtures/jsonObj-null-value.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "http/client"

url = "http://mockbin.com/har"
headers = HTTP::Headers{
"content-type" => "application/json"
}
reqBody = "{\"foo\":null}"

response = HTTP::Client.post url, headers: headers, body: reqBody
puts response.body
10 changes: 10 additions & 0 deletions src/targets/crystal/native/fixtures/multipart-data.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "http/client"

url = "http://mockbin.com/har"
headers = HTTP::Headers{
"content-type" => "multipart/form-data; boundary=---011000010111000001101001"
}
reqBody = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\nHello World\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"bar\"\r\n\r\nBonjour le monde\r\n-----011000010111000001101001--\r\n"

response = HTTP::Client.post url, headers: headers, body: reqBody
puts response.body
10 changes: 10 additions & 0 deletions src/targets/crystal/native/fixtures/multipart-file.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "http/client"

url = "http://mockbin.com/har"
headers = HTTP::Headers{
"content-type" => "multipart/form-data; boundary=---011000010111000001101001"
}
reqBody = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\n-----011000010111000001101001--\r\n"

response = HTTP::Client.post url, headers: headers, body: reqBody
puts response.body
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require "http/client"

url = "http://mockbin.com/har"
headers = HTTP::Headers{
"Content-Type" => "multipart/form-data"
}

response = HTTP::Client.post url, headers: headers
puts response.body
10 changes: 10 additions & 0 deletions src/targets/crystal/native/fixtures/multipart-form-data.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "http/client"

url = "http://mockbin.com/har"
headers = HTTP::Headers{
"Content-Type" => "multipart/form-data; boundary=---011000010111000001101001"
}
reqBody = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n"

response = HTTP::Client.post url, headers: headers, body: reqBody
puts response.body
6 changes: 6 additions & 0 deletions src/targets/crystal/native/fixtures/nested.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require "http/client"

url = "http://mockbin.com/har?foo%5Bbar%5D=baz%2Czap&fiz=buz&key=value"

response = HTTP::Client.get url
puts response.body
6 changes: 6 additions & 0 deletions src/targets/crystal/native/fixtures/query.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require "http/client"

url = "http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value"

response = HTTP::Client.get url
puts response.body
6 changes: 6 additions & 0 deletions src/targets/crystal/native/fixtures/short.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require "http/client"

url = "http://mockbin.com/har"

response = HTTP::Client.get url
puts response.body
10 changes: 10 additions & 0 deletions src/targets/crystal/native/fixtures/text-plain.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "http/client"

url = "http://mockbin.com/har"
headers = HTTP::Headers{
"content-type" => "text/plain"
}
reqBody = "Hello World"

response = HTTP::Client.post url, headers: headers, body: reqBody
puts response.body
14 changes: 14 additions & 0 deletions src/targets/crystal/target.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Target } from '../targets';
import { native } from './native/client';

export const crystal: Target = {
info: {
key: 'crystal',
title: 'Crystal',
extname: '.cr',
default: 'native',
},
clientsById: {
native,
},
};
1 change: 1 addition & 0 deletions src/targets/targets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ availableTargets()
expect(result).toStrictEqual(expected);
});
} catch (error) {
console.error(error);
throw new Error(
`Missing a test file for ${targetId}:${clientId} for the ${fixture} fixture.\nExpected to find the output fixture: \`/src/targets/${targetId}/${clientId}/fixtures/${fixture}${fixtureExtension}\``,
);
Expand Down
2 changes: 2 additions & 0 deletions src/targets/targets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CodeBuilderOptions } from '../helpers/code-builder';
import { Request } from '../httpsnippet';
import { c } from './c/target';
import { clojure } from './clojure/target';
import { crystal } from './crystal/target';
import { csharp } from './csharp/target';
import { go } from './go/target';
import { http } from './http/target';
Expand Down Expand Up @@ -60,6 +61,7 @@ export interface Target {
export const targets = {
c,
clojure,
crystal,
csharp,
go,
http,
Expand Down

0 comments on commit b9e1d7b

Please sign in to comment.