Skip to content

Commit

Permalink
feat: add function for sending a request
Browse files Browse the repository at this point in the history
Adds a function that sends a request using a Fetch environment.
  • Loading branch information
thewilkybarkid committed Mar 28, 2022
1 parent 1bfc956 commit 034a4f9
Show file tree
Hide file tree
Showing 9 changed files with 276 additions and 11 deletions.
14 changes: 14 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"prettier"
],
"overrides": [
{
"files": ["**/*.test.ts"],
"rules": {
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_"
}
],
"@typescript-eslint/no-floating-promises": "off"
}
}
],
"parserOptions": {
"project": "./tsconfig.json"
}
Expand Down
23 changes: 23 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,27 @@ nav_order: 1

A fetch wrapper for use with [fp-ts].

# Example

```ts
import fetch from 'cross-fetch'
import * as F from 'fetch-fp-ts'
import * as C from 'fp-ts/Console'
import * as RTE from 'fp-ts/ReaderTaskEither'
import { pipe } from 'fp-ts/function'

const env: F.FetchEnv = {
fetch,
}

pipe(
F.Request('HEAD')('foo'),
F.send,
RTE.chainFirstIOK(response => C.log(`Status code for ${response.url} is ${response.status}`)),
)(env)()
/*
Status code for https://www.example.com/ is 200
*/
```

[fp-ts]: https://gcanti.github.io/fp-ts/
24 changes: 24 additions & 0 deletions docs/modules/index.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ Added in v0.1.0

- [constructors](#constructors)
- [Request](#request)
- [send](#send)
- [model](#model)
- [Fetch (type alias)](#fetch-type-alias)
- [FetchEnv (interface)](#fetchenv-interface)
- [Request (type alias)](#request-type-alias)
- [Response (interface)](#response-interface)

Expand All @@ -33,6 +35,16 @@ export declare const Request: (method: string) => (url: string) => Request
Added in v0.1.0
## send
**Signature**
```ts
export declare const send: (request: Request) => ReaderTaskEither<FetchEnv, Error, Response>
```
Added in v0.1.0
# model
## Fetch (type alias)
Expand All @@ -45,6 +57,18 @@ export type Fetch = (...args: Request) => Promise<Response>
Added in v0.1.0
## FetchEnv (interface)
**Signature**
```ts
export interface FetchEnv {
fetch: Fetch
}
```

Added in v0.1.0

## Request (type alias)

**Signature**
Expand Down
115 changes: 105 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
"main": "dist/index.js",
"types": "dist/index.d.ts",
"sideEffects": false,
"peerDependencies": {
"fp-ts": "^2.11.0"
},
"devDependencies": {
"@commitlint/cli": "^16.2.3",
"@commitlint/config-conventional": "^16.2.1",
Expand All @@ -19,6 +22,7 @@
"@types/node-fetch": "^2.6.1",
"@typescript-eslint/eslint-plugin": "^5.16.0",
"@typescript-eslint/parser": "^5.16.0",
"cross-fetch": "^3.1.5",
"del-cli": "^4.0.1",
"docs-ts": "^0.6.10",
"dtslint": "github:gcanti/dtslint#2c3c3487e7650d6ca90c2877dbbd7c4c08360d0d",
Expand Down
21 changes: 21 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
/**
* @since 0.1.0
*/
import * as E from 'fp-ts/Either'
import * as R from 'fp-ts/Reader'
import * as RTE from 'fp-ts/ReaderTaskEither'
import * as TE from 'fp-ts/TaskEither'

import ReaderTaskEither = RTE.ReaderTaskEither

// -------------------------------------------------------------------------------------
// model
Expand Down Expand Up @@ -43,6 +49,14 @@ interface Headers extends Iterable<[string, string]> {
has(name: string): boolean
}

/**
* @category model
* @since 0.1.0
*/
export interface FetchEnv {
fetch: Fetch
}

// -------------------------------------------------------------------------------------
// constructors
// -------------------------------------------------------------------------------------
Expand All @@ -52,3 +66,10 @@ interface Headers extends Iterable<[string, string]> {
* @since 0.1.0
*/
export const Request: (method: string) => (url: string) => Request = method => url => [url, { headers: {}, method }]

/**
* @category constructors
* @since 0.1.0
*/
export const send: (request: Request) => ReaderTaskEither<FetchEnv, Error, Response> = ([url, init]) =>
R.asks(TE.tryCatchK(({ fetch }) => fetch(url, init), E.toError))
9 changes: 9 additions & 0 deletions test-d/ts4.0/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import nodeFetch from 'node-fetch'
import * as _ from '../../src'

declare const r1: _.Request

//
// Fetch
//

const f1: _.Fetch = fetch
const f2: _.Fetch = nodeFetch

//
// send
//

// $ExpectType ReaderTaskEither<FetchEnv, Error, Response>
_.send(r1)
37 changes: 37 additions & 0 deletions test/fc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as fc from 'fast-check'
import { Headers } from 'node-fetch'
import * as _ from '../src'

export * from 'fast-check'

export const request = (): fc.Arbitrary<_.Request> =>
fc.tuple(
fc.string(),
fc.record({
body: fc.option(fc.string(), { nil: undefined }),
headers: fc.dictionary(fc.string(), fc.string()),
method: fc.string(),
}),
)

const headerName = () =>
fc.stringOf(
fc.char().filter(char => /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]$/.test(char)),
{ minLength: 1 },
)
const headers = () =>
fc.option(fc.dictionary(headerName(), fc.string()), { nil: undefined }).map(init => new Headers(init))

export const response = (): fc.Arbitrary<_.Response> =>
fc.record({
headers: headers(),
status: fc.integer(),
statusText: fc.string(),
url: fc.string(),
text: fc.func(fc.string().map(text => Promise.resolve(text))),
})

export const error = (): fc.Arbitrary<Error> => fc.string().map(error => new Error(error))

export const throwablePrimitive = (): fc.Arbitrary<string | number | boolean> =>
fc.oneof(fc.string(), fc.integer(), fc.boolean())
Loading

0 comments on commit 034a4f9

Please sign in to comment.