Skip to content
/ fuchsia Public

The JSX/TSX web application framework built upon express - build declarative web servers using JSX/TSX syntax

License

Notifications You must be signed in to change notification settings

seppwc/fuchsia

Repository files navigation

fuchsia js

The JSX/TSX web application framework built upon express - build declarative web servers using JSX/TSX syntax

Hello World

import{JSX,FuchsiaFactory,useApplication}from"@fuchsiajs/core";
import{Controller,Route,HTTP}from"@fuchsiajs/common";

constAppController=()=>{
constHelloWorld=()=>(req):Promise<string>=>{
return"hello world";
};

return(
<Controllerpath="/">
<Routemethod={HTTP.GET}path="/"callback={HelloWorld}/>
</Controller>
);
};

exportconstmain=async()=>{
constapp:FuchsiaApplication=awaitFuchsiaFactory.create({
controllers:[AppController],
});

useApplication(app);
};

main();

Basic Routeing

FuchsiaJS makes use of JSX/TSX syntax to declaritively define controllers and routes.

Controllers

a basic controller is a function that returns a controller component, controllers have one predefined prop "path" which is the base path for all routes the fall under this controllers scope.

constAppController=()=>{
return(
<Controllerpath='/hello'>
...
</Controller>;
)
};

Routes

Routes are components which are nested in a controller, they define the individual route path and methods, they make use of the "method" prop to define which http method to use, and the "path" prop to define the url path for that route. if no method is set defaults to "all" http methods.

constAppController=()=>{
return(
<Controllerpath='/hello'>
<Routemethod="get"path="/"callback={...}/>
<Routemethod={HTTP.GET}path="/:id"callback={...}/>
<Routemethod={HTTP.POST}path="/"callback={...}/>
<Routemethod={HTTP.PUT}path="/:id"callback={...}/>
<Routemethod={HTTP.PATCH}path="/:id"callback={...}/>
<Routemethod={HTTP.DELETE}path="/:id"callback={...}/>
</Controller>;
)
};

Route Callbacks

Route callbacks are functions that get called when a route is executed. These are defined as a function which will receive one param (Request) within the controller scope and return promise, by default the return value will be included as a generic response type but including a json or render prop will return the desired type.

constAppController=()=>{

constHelloWorld=(req:Request):Promise<string>=>{
return'hello world'
}

return(
<Controllerpath='/hello'>
<Routemethod={HTTP.GET}path="/"callback={HelloWorld}/>
</Controller>;
)
};

Route Response Type

FuchsiaJS comes with a API response type to provide a consistent structure for data responses

typeFuchsiaResponse<T>={
message:'Success'|'Error',
payload?:T,
error?:string
}


constAppController=()=>{

constHelloWorld=(req:Request):Promise<FuchsiaResponse<string>>=>{
try{
return{message:'Success',payload:'Hello World'}
}catch(err){
return{message:'Error',errors:err}
}

}

return(
<Controllerpath='/hello'>
<Routemethod={HTTP.GET}path="/"callback={HelloWorld}/>
</Controller>;
)
};
//successfull
{
"message":"Success",
"payload":"PAYLOAD DATA"
}

//error
{
"message":"Error",
"error":{
"stringValue":"ERROR MESSAGE",
"kind":"ERROR KIND",
"value":"ERROR VALUE",
"path":"ERROR PATH",
"reason":{}
}
}

adding a controller to your application

The central hub of the application is in the index{.tsx|.jsx} file in the src folder.

inside is the async main function which calls FuchsiaFactory.create() to build our application object. the static create function takes in an object where we can define an array of controllers, which we will pass our controller into.

we then call await app.listen() to start listening for requests.

// index.tsx
exportconstmain=async()=>{
// FuchsiaFactory.create() returns Promise<FuchsiaApplication>
constapp:FuchsiaApplication=awaitFuchsiaFactory.create({
controllers:[AppController],
});

useApplication(app);
};
main();

Defining application configuration settings

there are several ways to define settings for you application.

  1. inside the object you pass to FuchsiaFactory.create()
  2. inside a Fuchsia.config.json file in the base project file
  3. inside a Fuchsia.config.js file in the base project file (import and spread only)
  4. inside a Fuchsia.config.yaml file in the base project file (not yet supported)

1. via FuchsiaFactory.create()

define a "config" property inside the object you pass to FuchsiaFactory.create()

// index.tsx
exportconstmain=async()=>{
constapp:FuchsiaApplication=awaitFuchsiaFactory.create({
controllers:[AppController],
config:{
viewEngine:"hbs",
views:"/views",
static:"/public",
json:true,
urlEncoded:true,
port:5555,
},
});
useApplication(app);
};
main();

2. via Fuchsia.config.json file

create a fuchsia.config.json file in the base folder of your project fuchsia will automatically look for this file are pass in all properties

/* fuchsia.config.json */
{
"json":true,
"viewEngine":"ejs",
"views":"/views",
"static":"/publilc",
"urlEncoded":true,
"port":5555
}

index.ts doesnt need to import anything or pass any properties as the json file so found by fuchsia by default.

/* index.tsx */
exportconstmain=async()=>{
constapp:FuchsiaApplication=awaitFuchsiaFactory.create({
controllers:[AppController],
});

useApplication(app);
};
main();

3. via Fuchsia.config.js file in the base project file (via import only)

export default an object containing settings properties

/* fuchsia.config.js */
exportdefault{
json:true,
viewEngine:"ejs",
views:"/views",
static:"/publilc",
urlEncoded:true,
port:5555,
};

at the moment fuchsia.config.js is not look for by default, so you will need to import it and pass the object to the config property

/* index.ts */

importconfigfrom"./fuchsia.config.js";

exportconstmain=async()=>{
constapp:FuchsiaApplication=awaitFuchsiaFactory.create({
controllers:[AppController],
config,
});

useApplication(app);
};
main();

4. via Fuchsia.config.yaml file in the base project file (not yet supported)

it is proposed to work the same as with fuchsia.config.json but for those who prefer to use yaml.

Databases

at the moment fuchsiajs only supports mongoDB via a mongoose. Adding a database connection to your application is very simple.

just importMongooseAdapterfrom@fuchsiajs/orm

create a "database" property in yourFuchsiaFactory.create()object and pass theMongooseAdaptercomponent to theadapterproperty and the connection uri string to theuriproperty

/* index.ts */
import{MongooseAdapter}from"@fuchsiajs/orm";

exportconstmain=async()=>{
constapp:FuchsiaApplication=awaitFuchsiaFactory.create({
controllers:[AppController],
database:{
adapter:<MongooseAdapter/>,
uri:process.env.DB_URI,
},
});

useApplication(app);
};
main();

any other DB specific options can be passed to anoptionsobject nest inside the database object

/* index.tsx */
import{MongooseAdapter}from"@fuchsiajs/orm";

exportconstmain=async()=>{
constapp:FuchsiaApplication=awaitFuchsiaFactory.create({
controllers:[AppController],
database:{
adapter:<MongooseAdapter/>,
uri:process.env.DB_URI,
options:{
useNewUrlParser:true,
useUnifiedTopology:true,
},
},
});

useApplication(app);
};
main();

if using a Fuchsia.config.json / Fuchsia.config.js file these options can be included using adatabaseOptionskey which takes this object, And ommited entirely from theFuchsiaFactory.create()object.

/* fuchsia.config.json */
{
"bodyParser":true,
"viewEngine":"ejs",
"views":"/views",
"static":"/publilc",
"urlEncoded":true,
"port":5555,
"databaseOptions":{
"useNewUrlParser":true,
"useUnifiedTopology":true
}
}

Hooks

FuchsiaJS comes with some built in hooks to help organise and transform code. This helps make the various building blocks of a project more modular and easier to test!

useApplication

This is the main entry point for your application, you will build and configure your application using the various controllers, services and model building blocks we provide, pass that configured app to your FuchsiaFactory.create Method and then pass the resulting app to the useApplciation hook, this will initialise the application and also provides a top level closure over our application in order to provide all the other utility hooks.

import{
JSX,
FuchsiaFactory,
FuchsiaApplication,
useApplication,
}from"../packages/core";
import{MongooseAdapter}from"../packages/orm";
import{AppController}from"./AppController";

exportconstmain=async()=>{
constapp:FuchsiaApplication=awaitFuchsiaFactory.create({
controllers:[AppController],
database:{
adapter:<MongooseAdapter/>,
uri:process.env.DB_URI,
},
});

// initialises the application and provides a top level closure around our application!!
useApplication(app);
};

main();

useService / createService

Call back methods can be declared inside the Controller scope like shown in above examples, and that works great, but it makes testing those functions a massive headache!, with the createService hook we can delare a service globally in our application and then with the useService hook we can call methods from a service we declared elsewhere in the application. pass in a string to declare the name of the service you wish to return the methods from, and then descructure those methods from the reponse.

// in vanilla js, services must be declared as an object with a "name" and a "methods" property

exportcreateService({
name:'app',
methods:{
GetOne:()=>"hi app 1",
GetMany:()=>"hi app 2"
}
});
// in typescript you can use decorators

@Service('app')
classservice1{

@Method()
GetOne(){
return"hi app 1"
}

@Method()
GetMany(){
return"hi app 2"
}
}


exportcreateService(service1)
const{GetOne}=useService('app')

return(
<Controllerpath='/'>
<Routejsonmethod={HTTP.GET}path='/'callback={GetOne}/>
</Controller>

About

The JSX/TSX web application framework built upon express - build declarative web servers using JSX/TSX syntax

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published