Â
This package helps to create server-side application.
Here you find JSX components on back-end side 🎉, cms, routing, proxy, html rendering and more.
Based on innet.
The simplest way is using innetjs
npx innetjs init my-app -t be
change my-app to work folder name
Go into my-app
and check README.md
Use server
handler to start an application.
import innet from 'innet'
import server from '@innet/server'
import app from './app'
innet(app, server)
To start http(s) server, use server
element.
Try it out in app.tsx
export default (
<server>
<action>
Hello World!
</action>
</server>
)
Any content inside the server will be turned back to user.
In this case the user will get Hello World
on any request.
Use npm start
to run this server.
To change the port of the web server you can use port
prop.
export default (
<server port={80}>
<action>
Hello World!
</action>
</server>
)
or you can use PORT
environment variable.
To have https connection you should provide SSL certificate.
const ssl = {
key: 'local.key',
cert: 'local.crt'
}
export default (
<server ssl={ssl}>
<action>
Hello World!
</action>
</server>
)
or you can use SSL_CRT
and SSL_KEY
environment variables.
You can show some message or do something right after the server starts.
export default (
<server onStart={console.log}>
<action>
Hello World!
</action>
</server>
)
You can log errors or do something else, when the server get an error.
export default (
<server onError={console.error}>
<action>
Hello World!
</action>
</server>
)
You can log any request with onRequest
prop.
export default (
<server onRequest={console.log}>
<action>
Hello World!
</action>
</server>
)
You can react on destroy the server with onDestroy
prop.
export default (
<server
onDestroy={() => console.log('destroy')}>
<action>
Hello World!
</action>
</server>
)
You can use html
element to return html content.
export default (
<server>
<action>
<html>
<head>
<title>Innet App</title>
</head>
<body>
Hello World!
</body>
</html>
</action>
</server>
)
You can use variables to split it anyhow.
const content = (
<html>
<head>
<title>Innet App</title>
</head>
<body>
Hello World!
</body>
</html>
)
export default (
<server>
<action>
{content}
</action>
</server>
)
You can add an HTTP header into response with header
element.
const content = (
<html.../>
) // check prev example
export default (
<server>
<action>
<header name='content-type' value='text/html'>
{content}
</header>
</action>
</server>
)
Also, you can put header around the content, it works the same.
const content = (
<html.../>
) // check prev example
export default (
<server>
<action>
<header name='content-type' value='text/html' />
{content}
</action>
</server>
)
You can return a file as a response.
export default (
<server>
<action>
<header name='cache-control' value='max-age=300'>
<file path='index.html' />
</header>
</action>
</server>
)
In this case cache-control
will be equal to max-age=300
even if the file does not exist.
You can put content into the file to apply it only if the file does exist.
export default (
<server>
<action>
<file path='index.html'>
<header name='cache-control' value='max-age=300' />
</file>
</action>
</server>
)
Put index.html
in the root of the project (my-app
folder).
The router helps to handle requests by route.
export default (
<server>
<action>
<router>
<file path='index.html' />
</router>
</action>
</server>
)
The router does nothing and returns self content. It starts work only with the next props.
This property says that the content of the route should be run if the request method equals to the prop.
export default (
<server>
<action>
<router method='GET'>
<file path='index.html' />
</router>
</action>
</server>
)
You can set path
to match with it.
export default (
<server>
<action>
<router method='GET' path='/'>
<file path='index.html' />
</router>
</action>
</server>
)
You will get the index.html
only on the root path with GET
method.
This prop has regex like syntax, so you can set the path as you wish.
export default (
<server>
<action>
<router path='/user/[0-9]+'>
<file path='index.html' />
</router>
</action>
</server>
)
To provide named params from url, use named capturing groups of regex.
export default (
<server>
<action>
<router path='/user/(?<id>[\w-]+)'>
<file path='index.html' />
</router>
</action>
</server>
)
You can react on any path which starts with provided one.
export default (
<server>
<action>
<router path='/test' ish>
<file path='index.html' />
</router>
</action>
</server>
)
/
, /something
, /test1
do not match.
/test
, /test/something
matches.
You can use a router inside another one and prefix
helps reduce path prop.
export default (
<server>
<action>
<router path='/test' prefix='/test' ish>
<router path='/'>
<file path='index.html' />
</router>
<router path='/404'>
<file path='404.html' />
</router>
</router>
</action>
</server>
)
Here you can get index.html
on /test
and 404.html
on /test/404
.
You can log the requests of any router.
export default (
<server>
<action>
<router path='/test' onMatch={console.log}>
<file path='index.html' />
</router>
</action>
</server>
)
By default, routers in the same router runs one by one independent to result of the previous route.
To avoid this you can use switch element.
export default (
<server>
<action>
<switch>
<router path='/'>
<file path='index.html' />
</router>
<file path='404.html' />
</switch>
</action>
</server>
)
You will get index.html
only on the root path,
any other path will return 404.html
.
CMS helps to return files from a folder by path.
export default (
<server>
<action>
<switch>
<cms dir='cms' />
<file path='404.html' />
</switch>
</action>
</server>
)
It will check if the file exist in cms folder then returns the file else returns 404.html
.
You can use prefix with router to handle specific path.
export default (
<server>
<action>
<switch>
<router path='/cms' ish>
<cms dir='cms' prefix='/cms' />
</router>
<file path='404.html' />
</switch>
</action>
</server>
)
You can input something into cms
, if requested file is exist then the content should be used.
export default (
<server>
<action>
<switch>
<cms dir='cms'>
<header name='cache-control' value='max-age=300' />
</cms>
<file path='404.html' />
</switch>
</action>
</server>
)
You can proxy request.
export default (
<server>
<action>
<switch>
<cms dir='cms' />
<proxy to='https://site.com' />
</switch>
</action>
</server>
)
In this case, if you have a file in cms folder then the file will return
else makes request to the site.com
.
You can redirect users to another resource.
export default (
<server>
<action>
<switch>
<cms dir='cms' />
<redirect to='https://site.com' />
</switch>
</action>
</server>
)
By default, status is 301
, you can change it with status
prop.
export default (
<server>
<action>
<switch>
<cms dir='cms' />
<redirect to='https://site.com' status={302} />
</switch>
</action>
</server>
)
Also, you can use string key of status.
export default (
<server>
<action>
<switch>
<cms dir='cms' />
<redirect to='https://site.com' status='found'/>
</switch>
</action>
</server>
)
Any component is just a function which returns content that should be run.
server.tsx
export const Server = ({ cmsPrefix }) => (
<server>
<action>
<switch>
<router path={cmsPrefix} ish>
<cms dir='cms' prefix={cmsPrefix} />
</router>
<file path='404.html' />
</switch>
</action>
</server>
)
and then you can use it inside app.tsx
.
import { Server } from './server'
export default <Server cmsPrefix='/cms' />
You can use it with any other functionality, for example with html
.
import { useChildren } from '@innet/jsx'
function Html ({ title }) {
const children = useChildren()
return (
<header name='content-type' value='text/html'>
<html>
<head>
<title>{title}</title>
</head>
<body>
{children}
</body>
</html>
</header>
)
}
export default (
<server>
<action>
<Html title='main'>
Hello World!
</Html>
</action>
</server>
)
The first argument is props, the second is children and the last one is a handler.
You can use components inside another component.
If you work on REST API, you can use success
or error
as an answer
export default (
<server>
<action>
<success />
</action>
</server>
)
You will get 204
status (noContent
), without content.
You can provide some data to the user by children.
const data = {
posts: []
}
export default (
<server>
<action>
<success>
{data}
</success>
</action>
</server>
)
You will get 200
status (ok
), with body equals data.
You can set status by status prop.
const data = {
id: '123'
}
export default (
<server>
<action>
<success status='created'>
{data}
</success>
</action>
</server>
)
You will get 201
status (created
), with data as a content.
You can use a number with status
prop.
const data = {
id: '123'
}
export default (
<server>
<action>
<success status={201}>
{data}
</success>
</action>
</server>
)
You can return an error to the user.
export default (
<server>
<action>
<error />
</action>
</server>
)
You will get 520
status (unknownError
).
You can provide some data to the user by children.
const data = {
message: 'Some error!'
}
export default (
<server>
<action>
<error>
{data}
</error>
</action>
</server>
)
You can change response status by status
prop.
const data = {
message: 'User not found!'
}
export default (
<server>
<action>
<error status='notFound'>
{data}
</error>
</action>
</server>
)
Also, you can use a number with the status prop.
const data = {
message: 'User not found!'
}
export default (
<server>
<action>
<error status={404}>
{data}
</error>
</action>
</server>
)
You can set cookie by cookie
element.
const Login = ({ token }) => (
<cookie key='token' value={token}>
<success />
</cookie>
)
export default (
<server>
<action>
<Login token='test' />
</action>
</server>
)
To remove cookie just provide key without value.
export default (
<server>
<action>
<cookie key='token'>
<success />
</cookie>
</action>
</server>
)
Action is an object which contains request
and response
.
Also, it contains a couple of fields and methods.
Action available in components.
import { useAction } from '@innet/server'
function Test () {
const { req, res } = useAction()
console.log(req, res)
}
You can get cookies as an object from an action.
import { useAction } from '@innet/server'
function Cookies () {
const { cookies } = useAction()
return <success>{cookies}</success>
}
You can set cookie with action.
import { useAction } from '@innet/server'
function Login () {
const action = useAction()
action.setCookie('user', 'token')
}
You can get current path with action.
import { useAction } from '@innet/server'
function Path () {
const { path } = useAction()
return path
}
You can get current search as an object.
import { useAction } from '@innet/server'
function Search () {
const { search } = useAction()
return <success>{search}</success>
}
You can parse body, and get values.
import { useAction } from '@innet/server'
async function Body () {
const action = useAction()
await action.parseBody()
return <success>{action.body}</success>
}
You can get files from a user.
import { useAction } from '@innet/server'
async function Body () {
const action = useAction()
await action.parseBody()
return <success>{action.files}</success>
}
You can get router data in a component
import { useRouter } from '@innet/server'
function Router () {
const { prefix, params } = useRouter()
return <success>{{ prefix, params }}</success>
}
Use named capturing groups of regex in a route path prop to add the params
.
export default (
<server>
<action>
<router path='/user/(?<id>[\w-]+)'>
<Router />
</router>
</action>
</server>
)
In this case, you will get id
equals test
in the params on /user/test
path.
If you find a bug or have a suggestion, please file an issue on GitHub.