<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Evgen Mykhailenko</title>
    <description>The latest articles on DEV Community by Evgen Mykhailenko (@evgen_mykhailenko).</description>
    <link>https://dev.to/evgen_mykhailenko</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2827639%2F3bf58e7b-3b14-4d3c-85b0-d121995c2f27.png</url>
      <title>DEV Community: Evgen Mykhailenko</title>
      <link>https://dev.to/evgen_mykhailenko</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/evgen_mykhailenko"/>
    <language>en</language>
    <item>
      <title>I'm a developer. I don't need Postman to run HTTP requests</title>
      <dc:creator>Evgen Mykhailenko</dc:creator>
      <pubDate>Sat, 08 Feb 2025 03:15:10 +0000</pubDate>
      <link>https://dev.to/evgen_mykhailenko/im-a-developer-i-dont-need-postman-to-run-http-requests-2830</link>
      <guid>https://dev.to/evgen_mykhailenko/im-a-developer-i-dont-need-postman-to-run-http-requests-2830</guid>
      <description>&lt;p&gt;Don't get me wrong, Postman is a perfect tool in its niche, but it is still a UI tool.&lt;/p&gt;

&lt;p&gt;Starting from the moment Postman came to market, I've been searching for a way to execute my requests in the way I’m used to — by writing code.&lt;/p&gt;

&lt;p&gt;The first tool I tried was the REST Client VS Code extension. It was very close to what I needed - finally, I could run requests from my IDE. I didn’t need to choose a verb from a dropdown, and I could store the files in Git. &lt;/p&gt;

&lt;p&gt;But there were still some drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I didn’t like how requests opened in a separate tab. If I switched focus to that tab, the next time VS Code would open my file in that tab group.&lt;/li&gt;
&lt;li&gt;Some syntax constructions, like ###, looked weird to me. I could get used to them, but they still felt unnatural.&lt;/li&gt;
&lt;li&gt;I still had to specify the full URL, even when using variables. I couldn’t just define a base URL and then use &lt;code&gt;GET /users&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I also wanted OpenAPI IntelliSense, but that still wasn’t possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, all of this led me to create my own language.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;a href="https://httl.dev" rel="noopener noreferrer"&gt;HTTL&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;For now, it is available as a &lt;a href="https://marketplace.visualstudio.com/items?itemName=HTTL.httl-vscode" rel="noopener noreferrer"&gt;VS Code Extension&lt;/a&gt;&lt;br&gt;
but very soon, I plan to roll out a CLI and support for other IDEs.&lt;/p&gt;

&lt;p&gt;In order to understand how this language happened and what the motivation behind it was, let's start from the basics and imagine how we could evolve the standard HTTP specification.&lt;/p&gt;

&lt;p&gt;I'll take this standard request to create a new user:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyjvbwxmz30volo2khhcy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyjvbwxmz30volo2khhcy.png" alt="Example 1" width="800" height="627"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First of all, let's do a little cleaning.&lt;/p&gt;

&lt;p&gt;Obviously, we don't need the &lt;code&gt;Content-Length&lt;/code&gt; header - the language should be able to calculate it by itself. We can also remove the &lt;code&gt;HTTP/1.1&lt;/code&gt; part and, for simplicity, use lowercase for verbs.&lt;/p&gt;

&lt;p&gt;Ok, now we have this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdk6s5g6d25nkaid8y7xq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdk6s5g6d25nkaid8y7xq.png" alt="Example 2" width="800" height="596"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not much better, but let's go ahead.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Host&lt;/code&gt; - this is an interesting one. While the HTTP spec requires it, the header does not indicate the communication protocol (e.g., HTTP or HTTPS), so we need to specify it directly somewhere else.&lt;/p&gt;

&lt;h4&gt;
  
  
  Option #1: Use a full url in the request line
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fei7eokp1xzy9d390uoh2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fei7eokp1xzy9d390uoh2.png" alt="Example 3" width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But what if we have more than one request and we don't want to repeat ourselves?&lt;/p&gt;

&lt;h4&gt;
  
  
  Option #2: Use a kind of templating, like in the REST client.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11rj0aa2n2ixjwol32j3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11rj0aa2n2ixjwol32j3.png" alt="Example 4" width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Again, we have to include &lt;code&gt;{{baseHost}}&lt;/code&gt; in every request.&lt;/p&gt;

&lt;p&gt;But don't you think we can do better?&lt;/p&gt;

&lt;p&gt;That's why we're here - we need to introduce a new language construction that extends the standard HTTP protocol: &lt;strong&gt;a directive&lt;/strong&gt;. Here's one: &lt;code&gt;@base&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi6ujqmto303xfd4e3nf9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi6ujqmto303xfd4e3nf9.png" alt="Example 5" width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will allow us to avoid repeating the base URL and prevent the need to specify it every time in any subsequent request.&lt;/p&gt;

&lt;p&gt;Ok, see what we've got.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2mcyh65ats33f1xex1f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2mcyh65ats33f1xex1f.png" alt="Example 6" width="800" height="627"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slightly better, but let's move forward.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Content-Type&lt;/code&gt; - we can make it common for every request to avoid repeating ourselves again. We can simply move it out of the request construction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foklotmknrbooykqkpmhn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foklotmknrbooykqkpmhn.png" alt="Example 7" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this change, &lt;code&gt;Content-Type&lt;/code&gt; becomes a global header and will be automatically set for any subsequent requests. It's very convenient for the Authentication header.&lt;/p&gt;

&lt;p&gt;On a final note, we are sending JSON, so why do we need &lt;code&gt;Content-Type&lt;/code&gt; at all? The language should automatically set the header for obviously recognizable payloads.&lt;/p&gt;

&lt;p&gt;Additionally, we can use JavaScript object syntax to remove unnecessary quotes.&lt;/p&gt;

&lt;p&gt;And here is what &lt;a href="https://httl.dev" rel="noopener noreferrer"&gt;HTTL&lt;/a&gt; is:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87b6yz0v0lpfrp31nx46.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87b6yz0v0lpfrp31nx46.png" alt="Example 8" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Much cleaner, but having just one request might not be as impressive as handling a chain of requests.&lt;/p&gt;

&lt;p&gt;And yes, this is the next feature the language should support: &lt;strong&gt;request chaining&lt;/strong&gt;. &lt;/p&gt;




&lt;h2&gt;
  
  
  Request Chaining
&lt;/h2&gt;

&lt;p&gt;Let's consider a real example where we first need to get an authentication token and then use it in subsequent requests.&lt;/p&gt;

&lt;p&gt;With all we've done above, let's dive in.&lt;/p&gt;

&lt;p&gt;This time, let's use the ReqRes.in API for this showcase.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ficde8gexcwzry1w98py4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ficde8gexcwzry1w98py4.png" alt="Example 9" width="800" height="718"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are slowly moving to a new feature: &lt;strong&gt;variables&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Variables
&lt;/h2&gt;

&lt;p&gt;We can store the response in a variable and use it in a later request.&lt;br&gt;
Here is how:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa65jl0yzk9evt8g2u2wl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa65jl0yzk9evt8g2u2wl.png" alt="Example 10" width="800" height="688"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Firstly&lt;/strong&gt;, we introduced a new construction here -  &lt;code&gt;as auth&lt;/code&gt;. It tells the runtime to store the response body in this variable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secondly&lt;/strong&gt;, we set a global &lt;code&gt;Authorization&lt;/code&gt; header to allow any subsequent request to use this header.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Authorization: Bearer {auth.token}&lt;/code&gt; - a few notes here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For string interpolation, we can use single brackets {}.&lt;/li&gt;
&lt;li&gt;If the response is JSON, we can use dot notation to access nested fields.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;You may wonder how to access other elements of the response, such as headers, timings, status, etc. I plan to add this in future releases&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, we can complete the scenario of create, update, and delete steps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1fojtx9ga8fmy4s7p5cu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1fojtx9ga8fmy4s7p5cu.png" alt="Example 11" width="800" height="1239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's much better! We are not overwhelmed with unnecessary constructions like the base URL, common headers, etc. &lt;/p&gt;

&lt;p&gt;That's one of the main ideas of HTTL: to remove unnecessary constructions and leave only meaningful elements. It keeps the code clean and lets us focus more on logic rather than mechanics.&lt;/p&gt;

&lt;p&gt;Wait, Assert? Yes! How can we create a language without testing capabilities?&lt;/p&gt;




&lt;h2&gt;
  
  
  Asserting
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;assert&lt;/code&gt; keyword can be added to the end of any request to verify the following elements: status, headers, and body.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmu7xoy6zf6t9pqea1w4l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmu7xoy6zf6t9pqea1w4l.png" alt="Example 11" width="800" height="688"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So far, it allows only strict equality, like &lt;code&gt;status: 200&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But stay tuned—the testing feature will evolve significantly in upcoming releases.&lt;/p&gt;




&lt;h2&gt;
  
  
  OpenAPI
&lt;/h2&gt;

&lt;p&gt;OpenAPI: we cannot overlook this important element of modern API development.&lt;/p&gt;

&lt;p&gt;This was my personal goal - to finally have IntelliSense for the OpenAPI spec. I’m a big fan of API documentation because it helps me make fewer mistakes.&lt;/p&gt;

&lt;p&gt;Since the HTTP spec does not include anything related to the OpenAPI spec, we need to introduce something new - the &lt;code&gt;@spec&lt;/code&gt; directive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwlvjfyugs8r5mser3bl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwlvjfyugs8r5mser3bl.png" alt="Example 12" width="800" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All we need to do is specify a URL to the openapi.json file, and now we can simply type &lt;code&gt;get /&lt;/code&gt; or invoke IDE IntelliSense, and the IDE will show all possible methods and URLs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvyx3li28tlfylfcls4jx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvyx3li28tlfylfcls4jx.png" alt="VSCode IntelliSense" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please note that the &lt;code&gt;@spec&lt;/code&gt; directive will automatically set the &lt;code&gt;@base&lt;/code&gt; URL based on the OpenAPI spec.&lt;/p&gt;




&lt;p&gt;So that's it for now! I hope you liked this journey.&lt;/p&gt;

&lt;p&gt;We haven't touched the module system, environment variables, and some cool features for VS Code, but let's leave those for the next articles. :)&lt;/p&gt;

&lt;p&gt;Also, if this is interesting, I can share more about the creation process, including ANTLR.js, the VS Code extension, implementing the Language Server Protocol (LSP), IDE IntelliSense, formatting the code, managing the runtime, and more, just let me know in the comments!&lt;/p&gt;

&lt;p&gt;Thank you and Happy coding!&lt;/p&gt;

&lt;p&gt;Nothing can stop you from reaching out to me :)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/httl-lang/HTTL" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bsky.app/profile/httl-lang.bsky.social" rel="noopener noreferrer"&gt;BlueSky&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://discord.gg/UQ6dmJpy" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=HTTL.httl-vscode" rel="noopener noreferrer"&gt;VSCode Marketplace&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rest</category>
      <category>api</category>
      <category>programminglanguages</category>
      <category>http</category>
    </item>
  </channel>
</rss>
