Stepzen-sveltekit - An Example Blog with SvelteKit, the DEV API, and a StepZen GraphQL Backend.

Overview

Building a Serverless Blog with StepZen, SvelteKit, and the DEV API

SvelteKit is a serverless first Svelte metaframework for building web applications with filesystem-based routing.

npm init svelte@next stepzen-svelte-devto

Select "Skeleton project."

✔ Which Svelte app template? › Skeleton project

You'll then be asked a series of questions to configure your application. Feel free to answer based on your own personal use case.

✔ Use TypeScript? … No / Yes
✔ Add ESLint for code linting? … No / Yes
✔ Add Prettier for code formatting? … No / Yes

For the sake of simplicity in this example I answered no for TypeScript, ESLint, and Prettier and I will not include any additional CSS libraries.

StepZen Setup

cd stepzen-svelte-devto
mkdir -p stepzen/schema
touch stepzen/index.graphql \
  stepzen/schema/user.graphql stepzen/schema/articles.graphql \
  stepzen/schema/followers.graphql stepzen/schema/comments.graphql \
  stepzen/schema/organizations.graphql stepzen/schema/podcasts.graphql
echo '{"endpoint": "api/stepzen-svelte-devto", "root": "stepzen"}' > stepzen.config.json
echo 'configurationset:' > config.yaml

StepZen Configuration

configurationset:
  - configuration:
      name: devto_config
      devto_api_key: xxxx
# stepzen/index.graphql

schema
  @sdl(
    files: [
      "schema/user.graphql"
      "schema/articles.graphql"
      "schema/followers.graphql"
      "schema/comments.graphql"
      "schema/organizations.graphql"
      "schema/podcasts.graphql"
    ]
  ) {
  query: Query
}
# stepzen/schema/user.graphql

type DevToUser {
  github_username: String!
  id: Int!
  joined_at: String!
  location: String!
  name: String!
  profile_image: String!
  summary: String!
  twitter_username: String!
  type_of: String!
  username: String!
  website_url: String!
}

type Query {
  getUser(
    id: String!, url: String
  ): DevToUser
    @rest(endpoint: "https://dev.to/api/users/$id")
}

Deploy StepZen Endpoint

stepzen start
query GET_AJCWEBDEV {
  getUser(id: "by_username", url: "ajcwebdev") {
    name
    summary
    github_username
    twitter_username
    location
    profile_image
    website_url
  }
}

Install dependencies and start development server

npm i
npm run dev

Open localhost:3000 to see the project.

01-hello-world-localhost-3000

Project Structure

Now we'll look at the code.

├── src
│   ├── routes
│   │   └── index.svelte
│   ├── app.html
│   └── global.d.ts
├── static
│   └── favicon.png
├── stepzen
│   ├── schema
│   │   ├── articles.graphql
│   │   ├── comments.graphql
│   │   ├── followers.graphql
│   │   ├── organizations.graphql
│   │   ├── podcasts.graphql
│   │   └── user.graphql
│   └── index.graphql
├── .gitignore
├── .npmrc
├── config.yaml
├── jsconfig.json
├── package-lock.json
├── package.json
├── README.md
├── stepzen.config.json
└── svelte.config.js

Pages

Pages are Svelte components written in .svelte files (or any file with an extension listed in config.extensions). By default, when a user first visits the application, they will be served a server-rendered version of the page in question, plus some JavaScript that 'hydrates' the page and initializes a client-side router. From that point forward, navigating to other pages is handled entirely on the client for a fast, app-like feel where the common portions in the layout do not need to be rerendered.

The filename determines the route. For example, src/routes/index.svelte is the root of your site.

<!-- src/routes/index.svelte -->

<script></script>

<section></section>

<style></style>

A .svelte file contains three parts:

  • <script> for JavaScript
  • <style> for CSS
  • Any markup you want to include with HTML.

Pages typically generate HTML to display to the user (as well as any CSS and JavaScript needed for the page). By default, pages are rendered on both the client and server, though this behavior is configurable.

Endpoints

Endpoints are modules written in .js (or .ts) files that export functions corresponding to HTTP methods.

touch src/routes/user.json.js

Endpoints run only on the server (or when you build your site, if pre-rendering). Pages can request data from endpoints. Endpoints return JSON by default, though may also return data in other formats.

// src/routes/user.json.js

export async function post() {}

A component that defines a page or a layout can export a load function that runs before the component is created and receive an implementation of fetch.

// src/routes/user.json.js

export async function post() {
  const response = await fetch()
  const data = await response.json()
  
  if (data) {
    return {
      body: data
    }
  }
}

This endpoint and corresponding function can be used to:

  • Access cookies on the server
  • Make requests against the app's own endpoints without issuing HTTP calls
  • Make a copy of the response and then send it embedded in the initial page load for hydration

Since endpoints only run on the server, they can be used for requests with private API keys that can't be exposed on the client. This also means you'll need to set those API keys to environment variables.

npm i -D dotenv
echo 'STEPZEN_ENDPOINT=\nSTEPZEN_API_KEY=' > .env

Include your StepZen endpoint and API keys in .env.

STEPZEN_ENDPOINT=
STEPZEN_API_KEY=
// src/routes/user.json.js

import 'dotenv/config'

const { STEPZEN_ENDPOINT, STEPZEN_API_KEY } = process.env

export async function post() {
  const response = await fetch(STEPZEN_ENDPOINT, {
    headers: {
      Authorization: `apikey ${STEPZEN_API_KEY}`
    }
  })

  const data = await response.json()
  
  if (data) {
    return {
      body: data
    }
  }
}

Fill in the rest of the POST request with our GraphQL people query.

// src/routes/user.json.js

import 'dotenv/config'

export async function post() {
  const response = await fetch(process.env.STEPZEN_ENDPOINT, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `apikey ${process.env.STEPZEN_API_KEY}`
    },
    body: JSON.stringify({
      query: `{
        getUser(id: "by_username", url: "ajcwebdev") {
          name
          summary
          github_username
          location
          profile_image
        }
      }`
    })
  })

  const data = await response.json()
  
  if (data) {
    return {
      body: data
    }
  }
}

Load Function

load is similar to getStaticProps or getServerSideProps in Next.js, except that it runs on both the server and the client.

<!-- src/routes/index.svelte -->

<script context="module">
  export const load = async ({ fetch }) => {
    try {
      const response = await fetch('/user.json', {
        method: 'POST',
        credentials: 'same-origin',
        headers: {
          'Content-Type': 'application/json'
        }
      })
      return {
        props: { ...(await response.json()) }
      }
    } catch (error) {
      console.error(`Error in load function for /: ${error}`)
    }
  }
</script>

<script>
  export let data
</script>

<main class="container">
  <ul class="content">
    <h2>{data.getUser.name}</h2>
    <h3>{data.getUser.github_username} - {data.getUser.location}</h3>
    <p>{data.getUser.summary}</p>
    <img src="{data.getUser.profile_image}" alt="profile pic">
  </ul>
</main>

The <script context="module"> is necessary because load runs before the component is rendered. Code that is per-component instance should go into a second <script> tag.

Articles

# stepzen/schema/articles.graphql

type ArticleShow {
  body_html: String!
  body_markdown: String!
  canonical_url: String!
  comments_count: Int!
  cover_image: String!
  description: String!
  organization: DevToOrganization
  path: String!
  public_reactions_count: Int!
  published_at: String!
  readable_publish_date: String!
  slug: String!
  tags: String!
  tag_list: JSON
  title: String!
  url: String!
}

type getArticlesResponse {
  body_html: String!
  body_markdown: String!
  canonical_url: String!
  comments_count: Int!
  cover_image: String!
  created_at: String!
  description: String!
  organization: DevToOrganization
  path: String!
  public_reactions_count: Int!
  published_at: String!
  readable_publish_date: String!
  slug: String!
  tags: String!
  tag_list: JSON
  title: String!
  url: String!
  user: DevToUser!
}

type Query {
  getArticleByPath(
    slug: String!, username: String!
  ): ArticleShow
    @rest(endpoint: "https://dev.to/api/articles/$username/$slug")

  getArticles(
    collection_id: Int
    page: Int
    per_page: Int
    state: String
    tag: String
    tags: String
    tags_exclude: String
    top: Int
    username: String
  ): [getArticlesResponse]
    @rest(endpoint: "https://dev.to/api/articles")
}
query GET_AJCWEBDEV_ARTICLES {
  getArticles(username: "ajcwebdev", per_page: 100) {
    title
    description
    readable_publish_date
    cover_image
    tags
    public_reactions_count
    slug    
    url
  }
}

Svelte Config

// svelte.config.js

import adapter from '@sveltejs/adapter-netlify';

/** @type {import('@sveltejs/kit').Config} */
const config = {
  kit: {
    adapter: adapter({
      split: false
    }),
    target: '#svelte'
  }
};

export default config;

target will hydrate the <div id="svelte"> element in src/app.html.

Official adapters for deployment

Svelte apps are built with adapters for optimizing your project to deploy with different environments. This project uses the adapter-netlify for Netlify.

Other Queries

query GET_STEPZEN_ORG {
  getOrganization(username: "stepzen") {
    name
    summary
    username
    url
    twitter_username
    profile_image
  }
}
query GET_STEPZEN_ORG_USERS {
  getOrgUsers(username: "stepzen") {
    name
    username
    summary
    location
    website_url
  }
}
query GET_STEPZEN_ORG {
  getOrgArticles(username: "stepzen") {
    title
    description
    tags
    readable_publish_date
    canonical_url
    cover_image
    public_reactions_count
    slug
    url
  }
}
query GET_PODCAST_EPISODES {
  getPodcastEpisodes(username: "fsjampodcast", per_page: 100) {
    title
    path
  }
}
You might also like...

An example of a mobile-first responsive web design

Mobile-First-RWD This demo is an example of a mobile-first responsive web design. This is a companion demo to the tutorial I wrote on HTML5 Rocks and

Sep 24, 2022

NextJS Starter Example for Running Zesty.io CMS

NextJS Starter Example for Running Zesty.io CMS

Zesty.io + NextJS Getting Started Node and NPM need to be installed. From your command line.

Dec 8, 2022

About Folder pattern for express rest api starterkit clean architecture, easy to scalable and easy to maintenance.

Express Rest Api Clean Architecture The following is a folder pattern for express rest api starterkit structure pattern that I usually use, so if you

Dec 20, 2022

A boilerplate for REST API Development with Node.js, Express, and MongoDB using TypesScript

node-mongo-boilerplate A simple boilerplate for NODEJS, EXPRESS and MONGODB REST API development . Quick Start Make sure you have node.js v14 + npm v8

Oct 16, 2022

Node Express Template (NET.ts) - a small template project which help you to speed up the process of building RESTful API

Node Express Template (NET.ts) - a small template project which help you to speed up the process of building RESTful API

Jan 4, 2023

@code-collabo's node-mongo API boilerplate template (typescript)

@code-collabo's node-mongo API boilerplate template (typescript) This is the manual download option for the API boilerplate template generated by @cod

May 31, 2022

Postgres Node.js Express TypeScript application boilerplate with best practices for API development.

Node TypeScript Boilerplate Postgres Developer Ready: A comprehensive template. Works out of the box for most Node.js projects. This project is intend

Aug 28, 2022

A few simple, but solid patterns for responsive HTML email templates and newsletters. Even in Outlook and Gmail.

Cerberus Responsive Email Patterns Coding regular emails is hard enough by itself. Making them responsive shouldn’t add to the headache. A few simple,

Dec 28, 2022

An upgradable boilerplate for Progressive web applications (PWA) with server side rendering, build with SEO in mind and achieving max page speed and optimized user experience.

An upgradable boilerplate for Progressive web applications (PWA) with server side rendering, build with SEO in mind and achieving max page speed and optimized user experience.

React PWA v2 A highly scalable, Progressive Web Application foundation,boilerplate, with the best Developer Experience. Demo: https://demo.reactpwa.co

Dec 26, 2022
Owner
Anthony Campolo
devvin' the web
Anthony Campolo
This repo conatain all the template of Dev.UI

Dev.Ui Templates This repo conatain all the template of Dev.Ui ?? Development Clone the repository git clone https://github.com/kumard3/dev-ui-templat

Kumar Deepanshu 24 Nov 26, 2022
X-Netflix is a streaming platform based on Netflix UI: built with ReactJS in frontend and nodeJS in backend.

X-Netflix X-Netflix is a streaming platform based on Netflix UI: built with ReactJS in frontend and nodeJS in backend. Built with FrontEnd: React.JS,

Mehdi BHA 52 Aug 19, 2022
This project is for backend developers with node js. It create the "Mongoose models, routers and controllers" with cli command line.

Node.js Boilerplate This project is for backend developers with node js. It create the "Mongoose models, routers and controllers" with cli command lin

Bilal Yaver 3 Sep 19, 2022
korrijs is a backend framework that built on express.js

körri-backend this is not a fork of any project. please support. -features: -automatic routing from file system "/routers" directory for eg.: you have

null 5 Aug 22, 2022
A template repository for Deno, GraphQL, and Svelte projects

Svelte is an innovative approach to frontend software development, the component model, and reactivity features creates simplistic approach to some hard problems. Svelte runs on the front end and is known as a Single Page Application.

hyper 15 Dec 20, 2022
React Starter Kit — isomorphic web app boilerplate (Node.js, Express, GraphQL, React.js, Babel, PostCSS, Webpack, Browsersync)

React Starter Kit — "isomorphic" web app boilerplate React Starter Kit is an opinionated boilerplate for web development built on top of Node.js, Expr

Kriasoft 21.7k Jan 1, 2023
Nestjs boilerplate template (mongodb, typeorm, graphql - code first, i18n, global exception handling etc.)

Description City-Library-Demo project for boilerplate. (node version: 16.14.0, npm version: 8.5.2) First Steps Create .env file in root directory. (Th

Mert Kaygusuz 7 Nov 21, 2022
A starter for nextjs that pulls in tailwindui, graphql

NextJS TypeScript TailwindUI GraphQL Boilerplate Demonstrates a NextJS application with TypeScript and TailwindUI with a ASP.Net Core GraphQL based AP

RDA Corporation 5 Nov 17, 2022
Express Graphql Clean Architecture

Folder pattern for express graphql starterkit clean architecture, easy to scalable and easy to maintenance, explore documentation for more about this starterkit https://typegraphql.com

Restu Wahyu Saputra 10 Aug 14, 2022
React + Redux starter kit / boilerplate with Babel, hot reloading, testing, linting and a working example app built in

A comprehensive starter kit for rapid application development using React. Why Slingshot? One command to get started - Type npm start to start develop

Cory House 9.8k Jan 3, 2023