DEV Community

Akash Kava for Web Atoms

Posted on • Edited on

5

RetroFit inspired REST Services in Web Atoms Core

Service Declaration

@DISingleton()
@BaseUrl("/api/v2020/app/")
export default class TaskService extends BaseService {

    @Get("user")
    public getUser(): Promise<IUser>;

    @Get("tasks")
    public getTasks(
        @Query("search") search: string,
        // default value should be specified in
        // decorator and not in argument declaration
        @Query("status", "open") status?: string
    ): Promise<ITask[]>

    @Get("tasks/{id}/attachments")
    public getAttachments(
        @Path("id") id: number
    ): Promise<ITaskAttachment[]>;

    @Put("tasks")
    public createTask(@Body task: ITask): Promise<ITask>;

    @Post("tasks/{id}/attachments")
    public uploadAttachment(
        @Path("id") id: number,
        @Body att: IAttachment,
        cancelToken: CancelToken): Promise<void>;
}
Enter fullscreen mode Exit fullscreen mode

As easy as it looks, its very easy to configure REST service.

Caching

    @Get("tasks", { jsCacheSeconds: 900 })
    public getTasks(
        @Query("search") search: string,
        // default value should be specified in
        // decorator and not in argument declaration
        @Query("status", "open") status?: string
    ): Promise<ITask[]>
Enter fullscreen mode Exit fullscreen mode

Caches response in JavaScript for 900 seconds.

Caching based on result

    @Get("tasks", { jsCacheSeconds: (r) => r.length ? 900 : 0 })
    public getTasks(
        @Query("search") search: string,
        // default value should be specified in
        // decorator and not in argument declaration
        @Query("status", "open") status?: string
    ): Promise<ITask[]>
Enter fullscreen mode Exit fullscreen mode

Cache response only if returned array has any items.

Fixed Headers

    @Get("tasks", {
            headers: {
               "x-cache": "none",
               "accept": "application/json"
            }
    })
    public getTasks(
        @Query("search") search: string,
        // default value should be specified in
        // decorator and not in argument declaration
        @Query("status", "open") status?: string
    ): Promise<ITask[]>
Enter fullscreen mode Exit fullscreen mode

Header in Parameters

    @Get("tasks")
    public getTasks(
        @Header("x-auth") auth: string,
        @Query("search") search: string,
        // default value should be specified in
        // decorator and not in argument declaration
        @Query("status", "open") status?: string
    ): Promise<ITask[]>
Enter fullscreen mode Exit fullscreen mode

Json Parsing Options

    @Get("tasks", { 
       jsonOptions: {
          namingStrategy: "underscore",
          indent: 2,
          dateConverter: {
             regex: dateFormatRegex,
             valueConverter: {
                fromSource:(v: string) => Date,
                fromTarget:(date: Date) => string
             }
          }
       }
    })
    public getTasks(
        @Header("x-auth") auth: string,
        @Query("search") search: string,
        // default value should be specified in
        // decorator and not in argument declaration
        @Query("status", "open") status?: string
    ): Promise<ITask[]>
Enter fullscreen mode Exit fullscreen mode

Returning Headers !!

    @Get("tasks", { 
       returnHeaders: true
    })
    public getTasks(
        @Header("x-auth") auth: string,
        @Query("search") search: string,
        // default value should be specified in
        // decorator and not in argument declaration
        @Query("status", "open") status?: string
    ): Promise<IApiResponse<ITask[]>>
Enter fullscreen mode Exit fullscreen mode

The only difference is, result type is always IApiResponse<T>, which contains headers and value.

Mocking

Mocking services makes unit testing and design time development very easy.

@DISingleton({ mock: "./mocks/MockTaskService" })
@BaseUrl("/api/v2020/app/")
export default class TaskService extends BaseService {
...
Enter fullscreen mode Exit fullscreen mode

Now you can keep MockTaskService inside mocks folder. And override every method to return design time data.

Dive into samples

https://www.webatoms.in/samples.html#contextId=0

GitHub logo web-atoms / core

MVVM Framework for JavaScript for Browser, Xamarin.Forms, Write TSX/TypeScript instead of Xaml and C#, Hot Reload Live Published Xamarin.Forms Apps.

Action Status npm version codecov

Web-Atoms Core

Web Atoms Core is a UI abstraction framework along with powerful MVVM pattern to design modern web and mobile applications.

Xamarin.Forms Features

  1. Use VS Code to develop Xamarin.Forms
  2. Write TypeScript instead of C#
  3. Write TSX (JSX) instead of Xaml
  4. Live hot reload for published app

Web Features

  1. Abstract Atom Component
  2. Abstract Device API (Browser Service, Message Broadcast)
  3. Theme and styles support without CSS
  4. One time, One way and Two way binding support
  5. Simple dependency Injection
  6. In built simple unit testing framework
  7. UMD module support
  8. Full featured MVVM Framework with powerful validation

Folder structure

  1. All views for web must be placed under "web" folder inside "src" folder.
  2. All views for Xamarin Forms must be placed under "xf" folder inside "src" folder.

Example folder structure

src
+--images
|  +--AddButton.svg
|
+--view-Models
|  +--TaskListViewModel.ts
|  +--TaskEditorViewModel.ts
|
+--web
|  +--tasks
|     +--TaskListView.tsx
|     +--TaskEditorView.tsx
|
+--xf
   +--tasks
      +--TaskListView.tsx
      +--TaskEditorView.tsx

Example View

Google AI Education track image

Build Apps with Google AI Studio 🧱

This track will guide you through Google AI Studio's new "Build apps with Gemini" feature, where you can turn a simple text prompt into a fully functional, deployed web application in minutes.

Read more →

Top comments (0)

typescript

11 Tips That Make You a Better Typescript Programmer

1 Think in {Set}

Type is an everyday concept to programmers, but it’s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields

...

Read the whole post now!

👋 Kindness is contagious

Take a moment to explore this thoughtful article, beloved by the supportive DEV Community. Coders of every background are invited to share and elevate our collective know-how.

A heartfelt "thank you" can brighten someone's day—leave your appreciation below!

On DEV, sharing knowledge smooths our journey and tightens our community bonds. Enjoyed this? A quick thank you to the author is hugely appreciated.

Okay