# The Uniform redirect SDK

> This section provides information on how to use redirects for common scenarios.

Source: https://docs.uniform.app/docs/guides/composition/url-management/redirects/redirect-sdk

The Uniform SDK lets developers work with [redirects](https://docs.uniform.app/docs/guides/composition/url-management/redirects).

## Execute redirects

The following example is a platform-agnostic approach to executing on redirects using the Uniform redirect SDK.

**Node.js**

```js
import { RedirectClient, WithMemoryCache } from '@uniformdev/redirect'
import * as dotenv from 'dotenv'

dotenv.config()
const client = new RedirectClient({
  apiKey: process.env.UNIFORM_API_KEY,
  projectId: process.env.UNIFORM_PROJECT_ID,
  // Store a cache of the data needed to resolve redirects in memory.  This could potentially get large.
  // Can operate without it, but will request data every hit.  Also of note the API is cached by fastly, so the repeated request response will be fast.
  // Memory cache only makes sense in middleware environments that retain objects between requests somehow.
  dataCache: new WithMemoryCache({ prePopulate: true, refreshRate: 20000 }),
})
// Expected that whatever product is being used has the ability get get the current URL and perform a redirect.
export default async function middleware(request: {
  getUrl: () => string,
  redirect: (target: string, statusCode: number) => void,
  keepGoingNormally: () => void,
}) {
  const url = request.getUrl()
  const result = await client.processUrlBestMatch(url)
  if (result) {
    request.redirect(
      result.url,
      result.definition?.redirect.targetStatusCode ?? 301
    )
    return
  }
  request.keepGoingNormally()
}
```

## Convert redirects for 3rd-party tools

The following examples represent converting Uniform redirects into a format that's executable by third-party hosting tools such as Netlify and Cloudflare:

**Next.js**

```js
import { RedirectClient } from '@uniformdev/redirect'
import * as dotenv from 'dotenv'
import * as fs from 'fs'
const convertUniformToNextjs = async () => {
  dotenv.config()
  const client = new RedirectClient({
    apiKey: process.env.UNIFORM_API_KEY,
    projectId: process.env.UNIFORM_PROJECT_ID,
  })
  const ret = []
  let redirects = (await client.getRedirects({ limit: 50, offset: 0 }))
    .redirects
  let count = 0
  while (redirects.length) {
    const redirect = redirects.pop()
    ret.push({
      source: redirect?.redirect.sourceUrl,
      destination: redirect?.redirect.targetUrl,
      permanent: redirect?.redirect.targetStatusCode === 301,
    })
    if (!redirects.length) {
      count++
      redirects = (await client.getRedirects({ limit: 50, offset: count * 50 }))
        .redirects
    }
  }
  if (!fs.existsSync('out')) {
    fs.mkdirSync('out')
  }
  fs.writeFile(
    'out/nextJsRedirects.json',
    JSON.stringify(ret, undefined, ' '),
    (e) => {
      if (e) {
        console.log(e)
      }
    }
  )
}
convertUniformToNextjs()
```

The previous examples of converting Uniform redirects result in an output like the following:

```json
[
  {
    "source": "/a",
    "destination": "/b",
    "permanent": true
  },
  {
    "source": "/this",
    "destination": "/that",
    "permanent": true
  },
  {
    "source": "/product/electronics/walkie-talkie",
    "destination": "/electronics/walkie-talkie",
    "permanent": true
  },
  {
    "source": "/source/path",
    "destination": "/target/url",
    "permanent": true
  }
]
```

**Netlify TOML**

```js
import { RedirectClient } from '@uniformdev/redirect'
import * as dotenv from 'dotenv'
import * as fs from 'fs'
const convertUniformToNetlifyToml = async () => {
  dotenv.config()
  const client = new RedirectClient({
    apiKey: process.env.UNIFORM_API_KEY,
    projectId: process.env.UNIFORM_PROJECT_ID,
  })
  const ret: string[][] = []
  let redirects = (await client.getRedirects({ limit: 50, offset: 0 }))
    .redirects
  let count = 0
  while (redirects.length) {
    const redirect = redirects.pop()
    ret.push([
      '[[redirects]]',
      `from = "${redirect?.redirect.sourceUrl}"`,
      `to = "${redirect?.redirect.targetUrl}"`,
      `status = ${redirect?.redirect.targetStatusCode}`,
    ])
    if (!redirects.length) {
      count++
      redirects = (await client.getRedirects({ limit: 50, offset: count * 50 }))
        .redirects
    }
  }
  if (!fs.existsSync('out')) {
    fs.mkdirSync('out')
  }
  fs.writeFile(
    'out/netlifyTomlRedirects.toml',
    ret.reduce((cur, o) => {
      return `${cur}${o.join('\n\t')}\n\n`
    }, ''),
    (e) => {
      if (e) {
        console.log(e)
      }
    }
  )
}
convertUniformToNetlifyToml()
```

This results in an output, such as the following, to be added to your TOML file:

```toml
[[redirects]]
	from = "/a"
	to = "/b"
	status = 301

[[redirects]]
	from = "/this"
	to = "/that"
	status = 301

[[redirects]]
	from = "/product/electronics/walkie-talkie"
	to = "/electronics/walkie-talkie"
	status = 301

[[redirects]]
	from = "/source/path"
	to = "/target/url"
	status = 301
```

**Netlify redirects**

```js
import { RedirectClient } from '@uniformdev/redirect'
import * as dotenv from 'dotenv'
import * as fs from 'fs'
const convertUniformToNetlify_redirects = async () => {
  const pad = (maxLen: number, curlen: number) => {
    const ret: string[] = []
    for (let i = curlen; i < maxLen; i++) {
      ret.push(' ')
    }
    return ret.join('')
  }
  dotenv.config()
  const client = new RedirectClient({
    apiKey: process.env.UNIFORM_API_KEY,
    projectId: process.env.UNIFORM_PROJECT_ID,
  })
  const ret: { source: string, target: string, statusCode: number }[] = []
  let redirects = (await client.getRedirects({ limit: 50, offset: 0 }))
    .redirects
  let count = 0
  let slen = 0
  let tlen = 0
  while (redirects.length) {
    const redirect = redirects.pop()?.redirect
    if (!redirect) continue
    slen = slen < redirect.sourceUrl.length ? redirect.sourceUrl.length : slen
    tlen = tlen < redirect.targetUrl.length ? redirect.targetUrl.length : tlen
    ret.push({
      source: redirect.sourceUrl,
      target: redirect.targetUrl,
      statusCode: redirect.targetStatusCode,
    })
    if (!redirects.length) {
      count++
      redirects = (await client.getRedirects({ limit: 50, offset: count * 50 }))
        .redirects
    }
  }
  if (!fs.existsSync('out')) {
    fs.mkdirSync('out')
  }
  fs.writeFile(
    'out/netlify_redirects',
    ret.reduce((cur, o) => {
      return `${cur}${o.source} ${pad(slen, o.source.length)} ${o.target} ${pad(
        tlen,
        o.target.length
      )} ${o.statusCode}\n`
    }, ''),
    (e) => {
      if (e) {
        // eslint-disable-next-line no-console
        console.log(e)
      }
    }
  )
}
convertUniformToNetlify_redirects()
```

This results in an output like the following, which should be added to your root folder in Netlify:

```csv
/a                                  /b                          301
/this                               /that                       301
/product/electronics/walkie-talkie  /electronics/walkie-talkie  301
/source/path                        /target/url                 301

```

**Cloudflare List**

```js
import { RedirectClient } from '@uniformdev/redirect'
import * as dotenv from 'dotenv'
import * as fs from 'fs'
const convertUniformTocloudflare = async () => {
  dotenv.config()
  const client = new RedirectClient({
    apiKey: process.env.UNIFORM_API_KEY,
    apiHost: process.env.UNIFORM_BASE_URL,
    projectId: process.env.UNIFORM_PROJECT_ID,
  })
  const ret: any[] = []
  let redirects = (await client.getRedirects({ limit: 50, offset: 0 }))
    .redirects
  let count = 0
  while (redirects.length) {
    const redirect = redirects.pop()
    ret.push({
      redirect: {
        source_url: redirect?.redirect.sourceUrl,
        target_url: redirect?.redirect.targetUrl,
        status_code: redirect?.redirect.targetStatusCode,
        preserve_query_string: redirect?.redirect.sourceRetainQuerystring,
      },
    })
    if (!redirects.length) {
      count++
      redirects = (await client.getRedirects({ limit: 50, offset: count * 50 }))
        .redirects
    }
  }
  if (!fs.existsSync('out')) {
    fs.mkdirSync('out')
  }
  fs.writeFile(
    'out/cloudflareList.json',
    JSON.stringify(ret, undefined, ' '),
    (e) => {
      if (e) {
        // eslint-disable-next-line no-console
        console.log(e)
      }
    }
  )
}
convertUniformTocloudflare()
```

Which results in an output like the following, which should be uploaded into a Cloudflare using their list API .

```json
[
  {
    "redirect": {
      "source_url": "/a",
      "target_url": "/b",
      "status_code": 301,
      "preserve_query_string": true
    }
  },
  {
    "redirect": {
      "source_url": "/this",
      "target_url": "/that",
      "status_code": 301,
      "preserve_query_string": true
    }
  },
  {
    "redirect": {
      "source_url": "/product/electronics/walkie-talkie",
      "target_url": "/electronics/walkie-talkie",
      "status_code": 301,
      "preserve_query_string": true
    }
  },
  {
    "redirect": {
      "source_url": "/source/path",
      "target_url": "/target/url",
      "status_code": 301,
      "preserve_query_string": true
    }
  }
]
```

**Cloudflare Redirects**

```js
import { RedirectClient } from '@uniformdev/redirect'
import * as dotenv from 'dotenv'
import * as fs from 'fs'
const convertUniformTocloudflare = async () => {
  dotenv.config()
  const client = new RedirectClient({
    apiKey: process.env.UNIFORM_API_KEY,
    apiHost: process.env.UNIFORM_BASE_URL,
    projectId: process.env.UNIFORM_PROJECT_ID,
  })
  const ret: any[] = []
  let redirects = (await client.getRedirects({ limit: 50, offset: 0 }))
    .redirects
  let count = 0
  while (redirects.length) {
    const redirect = redirects.pop()
    ret.push({
      expression: `http.request.uri.path eq "${redirect?.redirect.sourceUrl}"`,
      description: `Uniform redirect ${redirect?.redirect.sourceUrl} to ${redirect?.redirect.targetUrl}`,
      action: 'redirect',
      action_parameters: {
        from_value: { target_url: redirect?.redirect.targetUrl },
        status_code: redirect?.redirect.targetStatusCode,
        preserve_query_string: redirect?.redirect.sourceRetainQuerystring,
      },
    })
    if (!redirects.length) {
      count++
      redirects = (await client.getRedirects({ limit: 50, offset: count * 50 }))
        .redirects
    }
  }
  if (!fs.existsSync('out')) {
    fs.mkdirSync('out')
  }
  fs.writeFile(
    'out/cloudflareRedirects.json',
    JSON.stringify(
      {
        name: 'Uniform Redirect Rules',
        kind: 'zone',
        phase: 'http_request_dynamic_redirect',
        rules: ret,
      },
      undefined,
      ' '
    ),
    (e) => {
      if (e) {
        // eslint-disable-next-line no-console
        console.log(e)
      }
    }
  )
}
convertUniformTocloudflare()
```

Which results in an output like the following, which should be uploaded into a Cloudflare using their rules API.

```json
{
  "name": "Uniform Redirect Rules",
  "kind": "zone",
  "phase": "http_request_dynamic_redirect",
  "rules": [
    {
      "expression": "http.request.uri.path eq \"/a\"",
      "description": "Uniform redirect /a to /b",
      "action": "redirect",
      "action_parameters": {
        "from_value": {
          "target_url": "/b"
        },
        "status_code": 301,
        "preserve_query_string": true
      }
    },
    {
      "expression": "http.request.uri.path eq \"/this\"",
      "description": "Uniform redirect /this to /that",
      "action": "redirect",
      "action_parameters": {
        "from_value": {
          "target_url": "/that"
        },
        "status_code": 301,
        "preserve_query_string": true
      }
    },
    {
      "expression": "http.request.uri.path eq \"/product/electronics/walkie-talkie\"",
      "description": "Uniform redirect /product/electronics/walkie-talkie to /electronics/walkie-talkie",
      "action": "redirect",
      "action_parameters": {
        "from_value": {
          "target_url": "/electronics/walkie-talkie"
        },
        "status_code": 301,
        "preserve_query_string": true
      }
    },
    {
      "expression": "http.request.uri.path eq \"/source/path\"",
      "description": "Uniform redirect /source/path to /target/url",
      "action": "redirect",
      "action_parameters": {
        "from_value": {
          "target_url": "/target/url"
        },
        "status_code": 301,
        "preserve_query_string": true
      }
    }
  ]
}
```

## CLI commands for redirects

[Learn about the CLI commands for redirects](https://docs.uniform.app/docs/guides/cli/commands/redirect) in the CLI guide.
