Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions website/docs/how-to-guides/_category_.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"label": "How-To Guide",
"label": "How-To Guides",
"position": 3,
"link": {
"type": "generated-index"
"type": "generated-index",
"description": "5 minutes to practice the most important api-ts concepts."
}
}
102 changes: 102 additions & 0 deletions website/docs/how-to-guides/parsing.json-strings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Decoding JSON from Headers, Query Parameters, and URL Parameters

Though we know headers, url parameters, and query parameters will be received as a
`string` or `string[]` value, due to a limitation in api-ts, `httpRequest` only accepts
codecs that decode values starting from the `unknown` type. Consequently, decoding a
header, url parameter, or query parameter with a codec like `JsonFromString`, which can
only decode values typed as `string`, will produce a error like:

```
Type 'Type<Json, string, string>' is not assignable to type 'Mixed'.
Types of property 'validate' are incompatible.
Type 'Validate<string, Json>' is not assignable to type 'Validate<unknown, any>'.
Type 'unknown' is not assignable to type 'string'.
```

There's a straightforward pattern you can use when you have a value typed as `unknown`
but need to decode it with a codec that can only decode a narrower type. This pattern is
called <em>codec chaining</em>:

```typescript
declare const JsonFromString: t.Type<Json, string, string>;
declare const t.string: t.Type<string, string, unknown>;

const myCodec: t.Type<Json, string, unknown> = t.string.pipe(JsonFromString);
```

Here, `t.string` decodes a value from `unknown` to `string`, and then `JsonFromString`
decodes the same value from `string` to `Json`.

For example:

```typescript
import * as t from 'io-ts';
import { nonEmptyArray, JsonFromString, NumberFromString } from 'io-ts-types';
import { httpRequest, optional } from '@api-ts/io-ts-http';

// Define the Filter type for the JSON string
const Filter = t.type({
category: t.string,
tags: t.array(t.string),
price: t.type({
min: t.number,
max: t.number,
}),
});

// Define the SearchRequest codec
const SearchRequest = httpRequest({
params: {
userId: NumberFromString,
},
query: {
q: t.string,
filter: t.string.pipe(JsonFromString).pipe(Filter),
tags: nonEmptyArray(t.string),
sort: optional(t.string),
},
headers: {
authorization: t.string,
},
});

// Example request object
const example = {
params: {
userId: '84938492',
},
query: {
q: 'test',
filter:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: this is a great example!

'{"category":"books","tags":["crypto","trading"],"price":{"min":10,"max":50}}',
tags: ['tag1', 'tag2', 'tag3'],
sort: 'price',
},
headers: {
authorization: 'Bearer token',
},
};

// Decode the example
const decoded = SearchRequest.decode(example);
if (decoded._tag === 'Right') {
console.log(decoded);
/*
Expected decoded output
{
userId: 84938492,
q: 'test',
filter: {
category: 'books',
tags: ['crypto', 'trading'],
price: { min: 10, max: 50 },
},
tags: ['tag1', 'tag2', 'tag3'],
sort: 'price',
authorization: 'Bearer token',
};
*/
} else {
console.error('Decoding failed:', decoded.left);
}
```
17 changes: 11 additions & 6 deletions website/docs/intro.md
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Love it!

Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@
sidebar_position: 1
---

### Lorem ipsum
# Introduction

```python hello.py
# mark[16:24]
print("This is Code Hike")
```
`io-ts-http` brings type safety to HTTP data handling in TypeScript by embracing the
"[parse, don't validate]" philosophy. Rather than simply checking if incoming HTTP data
is valid, it also parses raw, less-structured data (like strings or JSON) into strongly
typed, precise objects using the `io-ts` library. This parsing happens at the system
boundary, ensuring all types have use cases in your code. Once parsed, you can trust the
data satisfies both [type and semantic analysis].

Lorem ipsum dolor sit amet.
[parse, don't validate]:
https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/
[type and semantic analysis]:
https://bitgo.github.io/api-ts/docs/tutorial-basics/create-an-api-spec/#what-problem-does-io-ts-http-solve