Lab - Using httpYac
I am looking for some open source API clients for regular use. httpYac allows more flexible scripting and can also run headless as a headless service. It also comes with support for OAuth 2.0 and OIDC.
Preparation
- Node.js, optionally Yarn
Installation
From https://httpyac.github.io/ then https://httpyac.github.io/guide/, install CLI:
yarn global add httpyac
We'll also try the VS Code extension. Install it by searching for httpyac within VS Code, or using the command below if you can run code
in command line:
code --install-extension anweber.vscode-httpyac
Create a project folder and setup a dummy todo-list Express app:
mkdir yac
cd yac
yarn init -y
yarn add express
with the file app.js
const express = require('express');
const PORT = 3000;
let nextId = 4;
let todos = [
{ id: 1, title: 'Exercise', done: true, },
{ id: 2, title: 'Learn Python', done: false, },
{ id: 3, title: 'Lunch', done: false, },
];
function findTodo(id) {
return todos.find(todo => todo.id === id);
}
function addTodo({ title, done }) {
const todo = { id: nextId++, title, done };
todos.push(todo);
return todo;
}
function deleteTodo(id) {
todos = todos.filter(t => t.id !== id);
}
const app = express();
app.use(express.json());
app.set('json spaces', 2);
app.get('/', (req, res) => {
res.json({ message: 'ok' });
});
app.get('/todo', (req, res) => {
res.json(todos);
});
app.post('/todo', (req, res) => {
const { title = '', done = false } = req.body;
const todo = addTodo({ title, done });
res.json(todo);
});
app.get('/todo/:id(\\d+)', (req, res) => {
const id = parseInt(req.params.id);
const todo = findTodo(id);
if (!todo) return res.status(404).send('Not Found');
res.json(todo);
});
app.put('/todo/:id(\\d+)', (req, res) => {
const id = parseInt(req.params.id);
const { title, done } = req.body;
const todo = findTodo(id);
if (!todo) return res.status(404).send('Not Found');
if (title !== undefined) todo.title = title;
if (done !== undefined) todo.done = done;
res.json(todo);
});
app.delete('/todo/:id(\\d+)', (req, res) => {
const id = parseInt(req.params.id);
deleteTodo(id);
res.end();
});
app.get('/_bad', (req, res) => {
throw Error('This is bad');
});
app.all('*', (req, res, next) => {
res.status(400).send('Bad Request');
});
app.use((err, req, res, next) => {
res.status(500).send('Something wrong!');
});
app.listen(PORT, () => {
console.log(`Service at http://localhost:${PORT}`);
});
Then run it
$ node app.js
Service at http://localhost:3000
If we just use curl
:
$ curl http://localhost:3000
{"message":"ok"}
$ curl -i http://localhost:3000
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 21
ETag: W/"15-FCv+/NlfTgD7mX/4JeAWgb2wmko"
Date: Tue, 08 Oct 2024 03:37:43 GMT
Connection: keep-alive
Keep-Alive: timeout=5
{
"message": "ok"
}
Preparing the http file home.http
:
GET http://localhost:3000/
$ httpyac --all ./home.http
---------------------
GET http://localhost:3000/
accept: */*
accept-encoding: gzip, deflate, br
user-agent: httpyac
HTTP/1.1 200 - OK
connection: keep-alive
content-length: 21
content-type: application/json; charset=utf-8
date: Tue, 08 Oct 2024 03:39:09 GMT
etag: W/"15-FCv+/NlfTgD7mX/4JeAWgb2wmko"
keep-alive: timeout=5
x-powered-by: Express
{
"message": "ok"
}
1 requests processed (1 succeeded)
Showing available options:
$ httpyac --help
Usage: httpyac send <fileName...> [options]
send/ execute http files
Arguments:
fileName path to file or glob pattern
Options:
-a, --all execute all http requests in a http file
--bail stops when a test case fails
-e, --env <env...> list of environments
--filter <filter> filter requests output (only-failed)
--insecure allow insecure server connections when using ssl
-i --interactive do not exit the program after request, go back to selection
--json use json output
--junit use junit xml output
-l, --line <line> line of the http requests
-n, --name <name> name of the http requests
--no-color disable color support
-o, --output <output> output format of response (short, body, headers, response,
exchange, none)
--output-failed <output> output format of failed response (short, body, headers,
response, exchange, none)
--raw prevent formatting of response body
--quiet
--repeat <count> repeat count for requests
--repeat-mode <mode> repeat mode: sequential, parallel (default)
--parallel <count> send parallel requests
-s, --silent log only request
-t, --tag <tag...> list of tags to execute
--timeout <timeout> maximum time allowed for connections
--var <variables...> list of variables (e.g foo="bar")
-v, --verbose make the operation more talkative
-h, --help display help for command
Try some variations below:
$ httpyac --all ./home.http -o body
---------------------
{
"message": "ok"
}
1 requests processed (1 succeeded)
$ httpyac --all ./home.http -o headers
---------------------
GET http://localhost:3000/
accept: */*
accept-encoding: gzip, deflate, br
user-agent: httpyac
HTTP/1.1 200 - OK
connection: keep-alive
content-length: 21
content-type: application/json; charset=utf-8
date: Tue, 08 Oct 2024 03:41:11 GMT
etag: W/"15-FCv+/NlfTgD7mX/4JeAWgb2wmko"
keep-alive: timeout=5
x-powered-by: Express
1 requests processed (1 succeeded)
$ httpyac --all ./home.http -o response
---------------------
HTTP/1.1 200 - OK
connection: keep-alive
content-length: 21
content-type: application/json; charset=utf-8
date: Tue, 08 Oct 2024 03:47:07 GMT
etag: W/"15-FCv+/NlfTgD7mX/4JeAWgb2wmko"
keep-alive: timeout=5
x-powered-by: Express
{
"message": "ok"
}
1 requests processed (1 succeeded)
POST - Create New Item
To add a new todo item, create a file todo-new-item.http
:
POST http://localhost:3000/todo
Content-Type: application/json
{
"title": "Dinner",
"done": false
}
GET http://localhost:3000/todo
And run it:
$ httpyac --all todo-new-item.http
---------------------
POST http://localhost:3000/todo
accept: */*
accept-encoding: gzip, deflate, br
content-length: 40
content-type: application/json
user-agent: httpyac
{
"title": "Dinner",
"done": false
}
HTTP/1.1 200 - OK
connection: keep-alive
content-length: 51
content-type: application/json; charset=utf-8
date: Tue, 08 Oct 2024 03:54:53 GMT
etag: W/"33-B64ZQVMIvzd8UgOtCCzSBxGpaws"
keep-alive: timeout=5
x-powered-by: Express
{
"id": 4,
"title": "Dinner",
"done": false
}
---------------------
GET http://localhost:3000/todo
accept: */*
accept-encoding: gzip, deflate, br
user-agent: httpyac
HTTP/1.1 200 - OK
connection: keep-alive
content-length: 260
content-type: application/json; charset=utf-8
date: Tue, 08 Oct 2024 03:54:53 GMT
etag: W/"104-g18obrYyxa/iaCigiU6DM/maeaU"
keep-alive: timeout=5
x-powered-by: Express
[
{
"id": 1,
"title": "Exercise",
"done": true
},
{
"id": 2,
"title": "Learn Python",
"done": false
},
{
"id": 3,
"title": "Lunch",
"done": false
},
{
"id": 4,
"title": "Dinner",
"done": false
}
]
2 requests processed (2 succeeded)