teleren/devto huggingface dataset:
JWT Auth in Apollo Server with TypeScript
Tags: typescript, node
Published: 2023-01-08 04:09:36

[✨ **Watch on YouTube**](https://youtu.be/zjmAw6wWtOU)

Since the JWT token comes in a header, we want to handle context in `ApolloServer`.

```ts
const server = new ApolloServer({
  // ...
  context: async ({ event: { headers } }): Promise<OperationContext> => {
    let userId = null
    try {
      userId = await userIdFromToken(
        headers["Authorization"].replace("Bearer ", "")
      )
    } catch {}

    return {
      userId,
    }
  },
})
```

We take `Authorization` from the header, remove the "Bearer" word, and pass it to the `userIdFromToken` function.

It takes a secret from env variables. Then we verify the token against the secret with jwt.verify.

```ts
import jwt from "jsonwebtoken"
import { assertEnvVar } from "../shared/assertEnvVar"

interface DecodedToken {
  id: string
}

export const userIdFromToken = async (token: string) => {
  const secret = assertEnvVar("SECRET")

  const decoded = jwt.verify(token, secret)

  return decoded ? (decoded as DecodedToken).id : null
}
```

If everything is alright, we should have an `id` in a decoded result.

Now, we should get the user id in the resolver as a part of the context argument.

```ts
export interface OperationContext {
  userId: string | null
  country: string | null
}
```

To check for userId, I run the `assertUserId` function. It will throw an error if the user id is missing.

```ts
import { AuthenticationError } from "apollo-server-lambda"
import { OperationContext } from "../graphql/OperationContext"

export const assertUserId = ({ userId }: OperationContext) => {
  if (!userId) {
    throw new AuthenticationError("Invalid token")
  }

  return userId
}
```

The API creates a token on the authorization request and sends it back to the user.

Here we have the `generateAuthData` function that takes the user id. It calculates token expiration time and signs the token with the secret from env variables.

```ts
import jwt from "jsonwebtoken"
import { assertEnvVar } from "../shared/assertEnvVar"

const jwtLifespanInSeconds = 15552000

const getTokenExpirationTime = (ms: number) =>
  Math.floor(Date.now() / 1000) + ms

export const generateAuthData = (id: string) => {
  const tokenExpirationTime = getTokenExpirationTime(jwtLifespanInSeconds)
  const secret = assertEnvVar("SECRET")

  return {
    token: jwt.sign({ id, exp: tokenExpirationTime }, secret),
    tokenExpirationTime,
  } as const
}
```
Send AWS SES Emails with NodeJS & TypeScript
Tags: typescript, aws
Published: 2023-01-08 04:09:04

[✨ **Watch on YouTube**](https://youtu.be/vtCLt9SEykg)

Here we send a signup confirmation email to a user.

```ts
import { getHTMLTemplate, fillHtmlTemplate, sendEmail } from "../email"

export const sendEmailConfirmationLink = async (
  email: string,
  authLink: string
) => {
  const html = await getHTMLTemplate("auth")

  await sendEmail({
    email,
    body: fillHtmlTemplate(html, {
      "auth-link": authLink,
      email,
    }),
    subject: "Log in to Increaser",
    source: `Login <noreply@increaser.org>`,
  })
}
```

First, we want to take an HTML template. The function takes the template name and reads it from the file. I make template names the same as `HtmlTemplate` type.

```ts
export const getHTMLTemplate = memoize((template: HtmlTemplate) => {
  return readFile(
    path.resolve(__dirname, `../../templates/${template}.html`),
    "utf8"
  )
})
```

I don't usually send emails with fancy styling to not appear in recipient spam or promotion tabs.

In the `auth-email` template, we expect two variables - auth-link and email.

```ts
<p>Click the link below to sign in to <b>Increaser</b>.</p>

<p>This link will expire in 20 minutes.</p>

<a href={{auth-link}}>Sign in to Increaser</a>

<p>Confirming this request will securely sign you in using {{email}}.</p>

- Increaser Team

```

Once we've read the file into a string we'll use the `fillHtmlTemplate` function to insert variables into an email html.

```ts
export const fillHtmlTemplate = (
  html: string,
  variables: Record<string, string>
) => {
  let result = html
  Object.entries(variables).forEach(([key, value]) => {
    result = result.split(`{{${key}}}`).join(value)
  })

  return result
}
```

We pass the recipient email, HTML body, subject, and source to the `sendEmail` function.

I ran my Lambda in the European region, but AWS SES doesn't work there. So I explicitly pass the Virginia region to the SES constructor.

```ts
interface SendEmailParameters {
  email: string
  body: string
  subject: string
  source: string
}

const ses = new aws.SES({ region: "us-east-1" })

export const sendEmail = ({
  email,
  body,
  subject,
  source,
}: SendEmailParameters) =>
  ses
    .sendEmail({
      Destination: {
        ToAddresses: [email],
      },
      Message: {
        Body: {
          Html: {
            Data: body,
          },
        },
        Subject: {
          Data: subject,
        },
      },
      Source: source,
    })
    .promise()
```

We pass `Destination`, `Message`, and `Source` to the SES method and make it into a promise.
How to Use SVG Icons in React App?
Tags: react, typescript
Published: 2023-01-08 04:08:32

[✨ **Watch on YouTube**](https://youtu.be/_bCQDa7wfRw)

We don't need special treatment for SVG. We can have SVG tag in JSX the same way we have `div` or anchor `tag`.

```tsx
export const CoffeeIcon = () => {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="1em"
      height="1em"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      className="feather feather-coffee"
    >
      <path d="M18 8h1a4 4 0 0 1 0 8h-1"></path>
      <path d="M2 8h16v9a4 4 0 0 1-4 4H6a4 4 0 0 1-4-4V8z"></path>
      <line x1="6" y1="1" x2="6" y2="4"></line>
      <line x1="10" y1="1" x2="10" y2="4"></line>
      <line x1="14" y1="1" x2="14" y2="4"></line>
    </svg>
  )
}
```

I store all the icons for my app in the `ui/icons` folder. If we open any of those files, we'll find a regular React component that I render as any other React component.

To find an SVG icon for my project, I usually go to websites like [Google Fonts](https://fonts.google.com/icons) or [Feather](https://feathericons.com/).

To get a bell icon, I would search for it, download the icon, then open it in the code editor.

Then I would create a component, copy-paste SVG content into the icon component, then fix all format errors with VS Code's auto-fix. We don't want a hardcoded size. Let's set it to `1em` `width` and `height` to make it the same size as the parent. To inherit the parent's color, we'll set the stroke to `currentColor`.
How to Get Item by ID From Dynamodb Table with TypeScript?
Tags: dynamodb, typescript
Published: 2023-01-08 04:08:00

[✨ **Watch on YouTube**](https://youtu.be/WvSo6TzCYrA)

My app has a table with users, and I usually query just a handful of fields instead of the whole user object. That's why we have a second parameter called `attributes`. It is an array of user keys.

```ts
export async function getUserById<T extends (keyof User)[]>(
  id: string,
  attributes?: T
): Promise<Pick<User, T[number]> | undefined> {
  const { Item } = await documentClient
    .get(mergeParams(getUserItemParams(id), projectionExpression(attributes)))
    .promise()

  return Item as Pick<User, T[number]>
}
```

To simplify interactions with DynamoDB, I have a handful of helpers.

`projectionExpression` converts an array to an object we can pass to the document client.

```ts
export const projectionExpression = (attributes?: string[]) => {
  if (!attributes) {
    return {}
  }

  const ProjectionExpression = attributes
    .map((attr) => `${attr.includes(".") ? "" : "#"}${attr}, `)
    .reduce((acc, str) => acc + str)
    .slice(0, -2)

  const attributesToExpression = attributes.filter(
    (attr) => !attr.includes(".")
  )

  const ExpressionAttributeNames = attributesToExpression.reduce<{
    [key: string]: string
  }>((acc, attr) => {
    acc["#" + attr] = attr
    return acc
  }, {})

  return attributesToExpression.length
    ? { ProjectionExpression, ExpressionAttributeNames }
    : { ProjectionExpression }
}
```

I have a function like `getUserItemParams` for every table. It returns an object we need to get, update or delete an item.

```ts
export const getUserItemParams = (id: string) => ({
  TableName: tableName.users,
  Key: { id },
})
```

Sometimes those helpers can return an object with a shared field `ExpressionAttributeNames`. To resolve such clashes, I use the `mergeParams` function.

```ts
export const mergeParams = (...params: any[]) =>
  params.reduce(
    (acc, param) =>
      Object.entries(param).reduce((acc, [key, value]) => {
        acc[key] = Array.isArray(value)
          ? [...acc[key], ...value]
          : typeof value === "object"
          ? { ...acc[key], ...value }
          : value
        return acc
      }, acc),
    {}
  )
```
Apollo Server Errors for Clients with TypeScript
Tags: apollo, typescript, graphql
Published: 2023-01-08 04:06:54

[✨ **Watch on YouTube**](https://youtu.be/1mr3iQKnyJo)

Here I have a resolver for coupon code redemption. It should throw an error when the code doesn't exist or has a claim. Apollo server provides a few errors we can use to communicate errors to a client.

```ts
import { OperationContext } from "../../../graphql/OperationContext"
import { assertUserId } from "../../../auth/assertUserId"
import * as appSumoCodesDb from "../db"
import { UserInputError } from "apollo-server-lambda"

interface Input {
  code: string
}

export const redeemAppSumoCode = async (
  _: any,
  { input: { code } }: { input: Input },
  context: OperationContext
) => {
  const userId = assertUserId(context)

  const appSumoCode = await appSumoCodesDb.getAppSumoCodeById(code)
  if (!appSumoCode || appSumoCode.userId !== userId) {
    throw new UserInputError("Invalid code")
  }

  // ...
}
```

We can go to the source code and see that they all extend ApolloErro. So if we need a custom error, we can copy one of the classes from here and change the name with a code.

```ts
export class UserInputError extends ApolloError {
  constructor(message: string, extensions?: Record<string, any>) {
    super(message, "BAD_USER_INPUT", extensions)

    Object.defineProperty(this, "name", { value: "UserInputError" })
  }
}
```

Apollo Server always responds with 200, but if API threw an error, we'll receive errors with a response. I formatted the error to include only the message and extensions. If we want to provide extra information, we can add an object as a second parameter to ApolloError, and it will appear in the extensions object. To omit stack trace from extension, set `NODE_ENV` to production.

```ts
const server = new ApolloServer({
  typeDefs,
  resolvers,
  // ...
  formatError: ({ message, extensions }) => {
    return {
      message,
      extensions,
    }
  },
})
```

I run Apollo Server on AWS Lambda and use Sentry for error monitoring. Don't forget to pass ignoreSentryErrors, otherwise, your lambda will crash if you reach Sentry's quote.

```ts
exports.handler = Sentry.AWSLambda.wrapHandler(server.createHandler(), {
  ignoreSentryErrors: true,
})
```
Populate DynamoDB with BatchWriteItem & TypeScript
Tags: dynamodb, typescript
Published: 2023-01-08 04:03:45

[✨ **Watch on YouTube**](https://youtu.be/Kksm3JRV3c4)

Let's populate a DynamoDB table using `BatchWriteItem`.

I have a list of coupon codes for my product, and I want to move them into a DynamoDB table.

```ts
import uuid from "uuid/v4"

import { tableName } from "../src/shared/db/tableName"
import { documentClient } from "../src/shared/db"

const batchWriteItemMax = 25

const appSumoCodesNumber = 10000

const populateAppSumoCodes = async () => {
  const codes = Array.from({ length: appSumoCodesNumber }, () => uuid())
  const items = codes.map((id) => ({ id }))

  const itemsBatchesNumber = Math.ceil(items.length / batchWriteItemMax)
  await Promise.all(
    Array.from({ length: itemsBatchesNumber }, (_, i) => i).map(
      async (batchIndex) => {
        const batchItems = items.slice(
          batchWriteItemMax * batchIndex,
          batchWriteItemMax * (batchIndex + 1)
        )

        await documentClient
          .batchWrite({
            RequestItems: {
              [tableName.appSumoCodes]: batchItems.map((Item) => ({
                PutRequest: {
                  Item,
                },
              })),
            },
          })
          .promise()
      }
    )
  )
}

populateAppSumoCodes()
```

First, I convert them into a list of items.

We can't just upload all of them at once. DynamoDB allows inserting a maximum of 25 items at once.

We need to calculate how many batches we should have. For example, if there are 60 items, we'll insert 3 batches.

After that, we create an array with the length of `itemsBatchesNumber`, and use `Promise.all` to iterate over it.

To populate the table, we slice a batch from a list of items and pass it to the batchWrite method of DynamoDB `documentClient`.

Now let's set environment variables and run the migration with ts-node.
Update DynamoDB Item with TypeScript
Tags: dynamodb, typescript
Published: 2023-01-08 04:01:42

[✨ **Watch on YouTube**](https://youtu.be/L2MuGLee1Oc)

My app has a table with users, and to update a user with a given id, I have the `updateUser` function. The second parameter takes an object with fields for the update.

```ts
export const updateUser = (id: string, params: Partial<User>) => {
  return documentClient
    .update({
      ...getUserItemParams(id),
      ...getUpdateParams(params),
    })
    .promise()
}
```

To simplify interactions with DynamoDB, I have a handful of helpers.

The `getUpdateParams` function takes an object with fields and returns `UpdateExpression`, `ExpressionAttributeNames`, and `ExpressionAttributeValues`, which we need to pass to the document client to update the item.

```ts
export const getUpdateParams = (params: { [key: string]: any }) => ({
  UpdateExpression: `set ${Object.entries(params)
    .map(([key]) => `#${key} = :${key}, `)
    .reduce((acc, str) => acc + str)
    .slice(0, -2)}`,

  ExpressionAttributeNames: Object.keys(params).reduce(
    (acc, key) => ({
      ...acc,
      [`#${key}`]: key,
    }),
    {}
  ),

  ExpressionAttributeValues: Object.entries(params).reduce(
    (acc, [key, value]) => ({
      ...acc,
      [`:${key}`]: value,
    }),
    {}
  ),
})
```

I have a function like `getUserItemParams` for every table. It returns an object we need to get, update or delete an item.

```ts
export const getUserItemParams = (id: string) => ({
  TableName: tableName.users,
  Key: { id },
})
```
Drop DynamoDB Column with TypeScript
Tags: dynamodb, typescript
Published: 2023-01-08 04:01:40

[✨ **Watch on YouTube**](https://youtu.be/mtwE1q5u8_k)

It's a NoSQL database that only needs a schema for the item's key. What we call "drop a column" in a relational database would be "remove an attribute from every item" in DynamoDB.

I have a productivity app that has a user table with 9k items. It has a few outdated attributes. Let's make a migration that will remove them!

```ts
import { tableName } from "../src/shared/db/tableName"
import { documentClient } from "../src/shared/db"
import { User } from "../src/users/User"
import { Key } from "aws-sdk/clients/dynamodb"

type Item = Pick<User, "id">

const removeAttribute = async (attributeName: string) => {
  const recursiveProcess = async (lastEvaluatedKey?: Key) => {
    const { Items, LastEvaluatedKey } = await documentClient
      .scan({
        TableName: tableName.users,
        ExclusiveStartKey: lastEvaluatedKey,
        ExpressionAttributeNames: {
          "#attributeName": attributeName,
          "#id": "id",
        },
        FilterExpression: "attribute_exists(#attributeName)",
        ProjectionExpression: "#id",
      })
      .promise()

    await Promise.all(
      (Items as Item[]).map(async ({ id }) => {
        await documentClient
          .update({
            TableName: tableName.users,
            Key: {
              id,
            },
            AttributeUpdates: {
              [attributeName]: {
                Action: "DELETE",
              },
            },
          })
          .promise()

        console.log(`✅ Remove ${attributeName} from ${id}`)
      })
    )

    if (LastEvaluatedKey) {
      await recursiveProcess(LastEvaluatedKey)
    }
  }

  recursiveProcess()
}

removeAttribute("goals")
```

Here we have a function that receives attribute name and removes it from every item. It's a recursive function because the scan returns a paginated result. First, we get items that have the attribute. Then we go over every item and call the update method with a delete action for the attribute. If there are still items to update, we go with the recursion.
I got a job offer from Turing!
Tags: job, discuss, webdev, beginners
Published: 2023-01-08 03:57:40

Hi I just got a job offer from Turing I am very excited and anxious should I take it?
Here are some Images 👇🏽

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m9vrzlm3qjbaz6iab194.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/it98d8cyaapns42gqsjc.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dnkxlu54f0vsjrjmux25.png)
How to install and Configure NVM on Mac OS
Tags: nvm, macos, node, developers
Published: 2023-01-08 03:24:04


nvm (Node Version Manager) is a tool that allows you to install and manage multiple versions of Node.js on your Mac. To install nvm on a Mac, you will need to follow these steps:

## Install Homebrew

nvm is not available in the default package manager for Mac, so you will need to install Homebrew first. To do this, open a terminal window and run the following command:

```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```

## Install nvm 

Once you have Homebrew installed, you can use it to install nvm by running the following command:

```
brew install nvm
```

Add nvm to your shell profile: To make nvm available every time you open a new terminal window, you will need to add the following line to your shell profile (e.g., ~/.bash_profile or ~/.zshrc):

```
source $(brew --prefix nvm)/nvm.sh
```

## Install Node.js

Once nvm is installed, you can use it to install the latest version of Node.js by running the following command:

```
nvm install node
```

## How to use specific version of NodeJS

To use a specific version of Node.js with nvm, you will need to follow these steps:

## List available Node.js versions

To see a list of all available Node.js versions that you can install with nvm, run the following command:

```
nvm ls-remote
```

## Install the desired version

To install a specific version of Node.js, such as version 16, use the following command:

```
nvm install 16
```

## Use the installed version

Once the desired version of Node.js is installed, you can use it by running the following command:

```
nvm use 16
```

Set the default version: If you want to use a specific version of Node.js by default, you can set it as the default version using the following command:

```
nvm alias default 16
```

## Further Readings:

- [Easy way to colorify Your Shell Prompt Experience on The Mac](https://collabnix.com/easy-way-to-colorify-your-shell-prompt-experience-on-the-mac/)
- [Docker init for Go Developers](https://collabnix.com/docker-init-for-go-developers/)
- [Using FastAPI inside a Docker container](https://collabnix.com/using-fastapi-inside-docker-containers/)
Day 3 #100DaysofCode
Tags: beginners, webdev, 100daysofcode
Published: 2023-01-08 03:17:12

Today was a long day and between family and other personal obligations, I was only able to fit in 1 hour of coding.

## What I Learned Today
* CSS Text Styles
  * System Font Stacks
  * Online Font Libraries

* Advanced CSS Selectors
  * Parent and Sibling Combinators
  * Pseudo-elements vs Pseudo-classes

* [CSS Diner](https://flukeout.github.io/#) - Interactive game

* CSS Positioning
  * Static and Relative Positioning
  * Absolute Positioning
  * Fixed Positioning
  * Sticky Positioning
Best Sublimation Printer 2023
Tags: sublimationprinter, sublimationprinting, printing, printer
Published: 2023-01-08 03:07:02

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2t7zrzzlyc7jxmrx7jga.png)

Whether you run a publishing and printing business or like to make digital prints for fun, there is one thing that you need for both, a sublimation printer. The market is flooded with different models of sublimation printers from different brands. If you are a novice, then you need the [best sublimation printer for beginners](https://printerways.com/best-sublimation-printer-for-beginners/).

The ease that a sublimation printer appropriate to the skills of a beginner brings to the table is unparalleled. This is why I have compiled a list of the 9 best sublimation printers for beginners in this article. Along with that, there is also a detailed buying guide.


Sublimation for beginners can be an annoying job, but not if you have the best sublimation printer for beginners. You are going to find a variety of sublimation printers for sale in the market. With the help of the buying guide, and the products reviewed above, you will be able to pick the best model. I am sharing my top 3 recommendations to make your job easier.

1. Epson EcoTank ET-2760 comes at a low price, offers auto-duplex printing, and can print, scan, copy and fax.
2. Epson WorkForce WF-3760 Wireless uses PrecisionCore technology, Amazon Dash Replenishment Technology and offers dual-sided printing.
3. HP Deskjet 3755 has a wide sheet size range and offers wireless connectivity and voice control.