Ben Taylor

Ben Taylor

1583364000

How to Create REST API in Node.js with TypeScript and Fortjs

In this article, we will use fortjs - a nodejs MVC framework that is fully compatible with TypeScript and next gen JavaScript - es6, es7.

Code

SetUp

Clone or download the TypeScript starter project of fortjs here.

After you have downloaded the project. Open the Console and move to project directory and do the following steps,

  1. run the command - npm install
  2. run the command - npm run start

Open the URL - localhost:4000 in browser. You will see something like below.

**REST **

We are going to create a REST endpoint for entity user - which will perform the CRUD operations for user such as adding user, deleting user, getting user, and updating user.

According to to REST,

  1. Adding user - should be done using http method “POST”
  2. Deleting user - should be done using  http method “REMOVE”
  3. Getting user - should be done using http method  “GET”
  4. Updating user - should be done using http method “PUT”

For creating an endpoint, we need to create a Controller. You can read about controller here.

Create a file user_controller.ts inside the contollers folder and Copy the below code inside the file.

import { Controller, textResult, DefaultWorker} from 'fortjs'    
export class UserController extends Controller {    
      @DefaultWorker()    
      async default() {    
          return textResult('you have successfully created a user controller');    
      }    
}    

In the above code,

  • We have created a class “UserController” which is extending another class Controller from fortjs.
  • We have created a method default which is returning some result by using the method textResult from fortjs. textResult return http response with content-type ‘text/plain’.
  • We have used a decorator DefaultWorker from fortjs. A worker makes the method visible so that it can be called using http request (no worker means it just a function which is only available for this class). A default worker is a worker which add the route “/” for target method. Please take a look at worker doc - http://fortjs.info/tutorial/worker/

We have created a controller but it’s still unknown by fortjs. In order to use this controller, we need to add this to routes. Open routes.ts inside root folder and add UserController to routes.

import {DefaultController } from "./controllers/default_controller";  
import { UserController } from "./controllers/user_controller";  
  
export const routes = [{  
    path: "/default",  
    controller: DefaultController  
},{  
    path: "/user",   
    controller: UserController  
}]  

You can see, we have added the path “/user” for UserController. It means when the url contains path “/user”, UserController will be called.

Now open the URL — localhost:4000/user. You can see the output which is returned from default method inside “UserController”.

Note: One thing to notice here is that the code looks very simple and nice. This is possible due to TypeScript and fortjs. And another fun is that you will get IntelliSense support and this all make life easy for a developer :).

Service

Before moving further, let’s write service code, which will help us to do CRUD operations.

Create a folder “models” and then a file “user.ts” inside the folder. Paste the below code inside the file.

import { Length, Contains, IsIn, IsEmail } from "class-validator";  
  
export class User {  
    id?: number;  
  
    @Length(5)  
    password?: string;  
  
    @Length(5)  
    name: string;  
  
    @IsIn(["male", "female"])  
    gender: string;  
  
    @Length(10, 100)  
    address: string;  
  
    @IsEmail()  
    emailId: string;  
  
    constructor(user: any) {  
       this.id = Number(user.id);  
       this.name = user.name;  
       this.gender = user.gender;  
       this.address = user.address;  
       this.emailId = user.emailId;  
       this.password = user.password;  
    }  
}  

I am using a npm plugin - “class-validator” to validate the model. This model “user” will be used by service and controller for transfer of data.

Create a folder “services” and then a file “ user_service.ts” inside the folder. Paste the below code inside the file.

import { User } from "../models/user";  
  
interface IStore {  
    users: User[];  
}  
  
const store: IStore = {  
    users: [{  
        id: 1,  
        name: "durgesh",  
        address: "Bengaluru india",  
        emailId: "durgesh@imail.com",  
        gender: "male",  
        password: "admin"  
    }]  
}  
  
export class UserService {
  
    getUsers() {  
        return store.users;  
    }
  
    addUser(user: User) {  
        const lastUser = store.users[store.users.length - 1];  
        user.id = lastUser == null ? 1 : lastUser.id + 1;  
        store.users.push(user);  
        return user;  
    } 
 
    updateUser(user: User) {  
        const existingUser = store.users.find(qry => qry.id === user.id);  
        if (existingUser != null) {  
            existingUser.name = user.name;  
            existingUser.address = user.address;  
            existingUser.gender = user.gender;  
            existingUser.emailId = user.emailId;  
            return true;  
        }  
        return false;  
    }  

    getUser(id: number) {  
        return store.users.find(user => user.id === id);  
    }  

    removeUser(id: number) {  
        const index = store.users.findIndex(user => user.id === id);  
        store.users.splice(index, 1);  
    }  
}  

Above code contains a variable store, which contains collection of users and the method inside the service do operation like — add, update, delete, get on that store. Basically i have made a fake db and doing some crud operation.

GET

We are going to create an endpoint for getting user.

Let’s rename the default methods to “getUsers” which will return all users. Replace the code inside user_controller.ts by below code.

import { Controller, jsonResult, DefaultWorker} from 'fortjs'  
  
export class UserController extends Controller {  
    @DefaultWorker()  
    async getUsers() {  
       const service = new UserService();  
       return jsonResult(service.getUsers());  
    }  
}  

As you can see, we are using DefaultWorker since it makes the method visible for http request and adds route “/” with http method “GET”. So all these things using one decorator.

Now open the URL -  localhost:4000/user or you can use any http client such as postman.

This is image title

This method is only for http method — “GET” (since we are using DefaultWorker). If you will call this same endpoint for methods other than “GET”, you will get the status code 405.

POST

We need to create a method, which will add the users and only works for http method “POST”. So now “UserController” looks like this:

import { Controller, jsonResult, DefaultWorker, HTTP_METHOD, HTTP_STATUS_CODE, Worker, Route } from 'fortjs'  
    
export class UserController extends Controller {  
    
      @DefaultWorker()  
      async getUsers() {  
          const service = new UserService();  
          return jsonResult(service.getUsers());  
      }  
         
      @Worker([HTTP_METHOD.Post])  
      @Route("/")  
      async addUser() {  
          const user = {  
              name: this.body.name,  
              gender: this.body.gender,  
              address: this.body.address,  
              emailId: this.body.emailId,  
              password: this.body.password  
          };  
          const service = new UserService();  
          const newUser = service.addUser(user);  
          return jsonResult(newUser, HTTP_STATUS_CODE.Created);  
      }  
}  

In the above code,

  • We have created a method  “addUser” and added a decorator “Route” with parameter “/” which will add the route to method “addUser”. This means that, method “addUser” will be called when url will be - localhost:4000/user/.
  • In order to make this method visible - we are using decorator “Worker”. The parameter “HTTP_METHOD.Post” makes the method only work when the request method will be POST.
  • The method addUser - takes data from body (post data) and add the user to store by calling service. After the successful addition, it returns the added user with http code - 201 (Resource Created).

In summary, we have created a method “addUser” that is used to add users. It only works for http method post & route “/”.

You can test this by sending a post request to URL - “localhost:4000/user/” with user model value as body of the request.

This is image title

So we have successfully created the POST endpoint. But one thing to note here is that we are not doing any validations for the user. It might be that invalid data is supplied in post request.

We can write code inside “addUser” method to validate input data or write a separate method inside a controller (like validateUser) for validation.

Let’s add the validation code.

import { Controller, jsonResult, DefaultWorker, HTTP_METHOD, HTTP_STATUS_CODE, Worker, Route } from 'fortjs'  
import { User } from '../models/user';  
import { validate } from "class-validator";   
  
export class UserController extends Controller {  
  
    @DefaultWorker()  
    async getUsers() {  
        const service = new UserService();  
        return jsonResult(service.getUsers());  
    }  
  
    @Worker([HTTP_METHOD.Post])  
    @Route("/")  
    async addUser() {  
        const user = {  
            name: this.body.name,  
            gender: this.body.gender,  
            address: this.body.address,  
            emailId: this.body.emailId,  
            password: this.body.password  
        }  
        as User;  
        const errorMsg = await this.validateUser(user);  
        if (errorMsg == null) {  
            const service = new UserService();  
            const newUser = service.addUser(user);  
            return jsonResult(newUser, HTTP_STATUS_CODE.Created);  
        } else {  
            return textResult(errMessage, HTTP_STATUS_CODE.BadRequest);  
        }  
    }  
  
  
    async validateUser(user: User) {  
        const errors = await validate('User', user);  
        if (errors.length === 0) {  
            return null;  
        } else {  
            const error = errors[0];  
            const constraint = Object.keys(error.constraints)[0];  
            const errMessage = error.constraints[constraint];  
            return errMessage;  
        }  
    }  
}  

Ok, so we have added the code for data validation. It will work as expected but dont you think the code looks little bit messy?

FortJs provides components for validation and any extra work, so that your code looks much cleaner and easy to manage.

FortJs says -  “A worker should only have code related to its main purpose and extra code should be written into components.”

Let’s implement the above validation using components. Since we are doing operations on worker, we need to use Guard component.

Guard

Create a folder “guards” and a file “ model_user_guard.ts” inside the folder. Write the below code inside the file.

import { Guard, HttpResult, MIME_TYPE, HTTP_STATUS_CODE, textResult } from "fortjs";  
import { User } from "../models/user";  
import { validate } from "class-validator";  
  
export class ModelUserGuard extends Guard {  
    async check() {  
        const user: User = new User(this.body);  
        // here i am using a plugin to validate but you can write your own code too.   
        const errors = await validate('User', user);  
        if (errors.length === 0) {  // allow the request to pass through guard
            // pass this to method, so that they dont need to parse again  
            this.data.user = user;  
            return null;  
        }  
        else {  // block the request
            const error = errors[0];  
            const constraint = Object.keys(error.constraints)[0];  
            const errMessage = error.constraints[constraint];  
            return textResult(errMessage, HTTP_STATUS_CODE.BadRequest);  
        }  
    }  
}  

In the above code,

  • We are writing code inside the check method, which is part of guard lifecycle. We are validating the user inside it.
  • If user is valid then we are passing the user by using “data” property and returning null. Returning null means guard has allowed this request and the worker should be called.
  • If user is  not valid, we are returning an error message as text response with http code- “badrequest”. We are returning textResult, which means the fortjs will consider this as response and worker won’t be called.

Now we need to add this guard to method “addUser”.

@Guards([ModelUserGuard])  
@Worker([HTTP_METHOD.Post])  
@Route("/")  
async addUser() {  
    const user: User = this.data.user;  
    const service = new UserService();  
    return jsonResult(service.addUser(user), HTTP_STATUS_CODE.Created);  
}  

In the above code,

  • I have added the guard, “ModelUserGuard” using the decorator Guards .
  • With the guard in process, we don’t need to parse the data from body anymore inside worker, we are reading it from this.data which we are passing from “ModelUserGuard”.
  • The method “addUser” will be only called when Guard allow means if all data is valid.

You can see that our worker method looks very light after using component.

PUT

Now we need to create a method, which will update the user and will only work for http method — “PUT”.

Let’s add another method - “updateUser” with route “/” , guard — “ModelUserGuard” (for validation of user) and most important - worker with http method — “PUT”

@Worker([HTTP_METHOD.Put])  
@Guards([ModelUserGuard])  
@Route("/")  
async updateUser() {  
      const user: User = this.data.user;  
      const service = new UserService();  
      const userUpdated = service.updateUser(user);  
      if (userUpdated === true) {  
          return textResult("user updated");  
      }  
      else {  
          return textResult("invalid user");  
      }  
}  

The above code is very simple. It is just calling the service code to update the user. But one important thing to notice is that we have reutilized the guard - “ModelUserGuard” and it makes our code very clean.

So we are done with,

  • GET - Returns all users
  • POST - add users
  • PUT - update user

Currently, the GET request returns all the users but what if we want to get only one user.

Let’s see, how to do it.

We have created a method “getUsers” for returning all users. Now let’s create another method “getUser”, which will return only one user.

@Worker([HTTP_METHOD.Get])  
@Route("/{id}")  
async getUser() {  
      const userId = Number(this.param.id);  
      const service = new UserService();  
      const user = service.getUser(userId);  
      if (user == null) {  
          return textResult("invalid id");  
      }  
      return jsonResult(user);  
}  

In the above code, we are using a placeholder in route. Now “getUser” will be called when url will be something like localhost:4000/user/1 The placeholder value is being consumed by using “this.param” .

REMOVE

We will use the same concept as get.

@Worker([HTTP_METHOD.Delete])  
@Route("/{id}")  
async removeUser() {  
      const userId = Number(this.param.id);  
      const service = new UserService();  
      const user = service.getUser(userId);  
      if (user != null) {  
          service.removeUser(userId);  
          return textResult("user deleted");  
      }  
      else {  
          return textResult("invalid user");  
      }  
}  

In the above code, we are just calling the service to remove the user after getting the id from route.

Finally, we have successfully created a REST endpoint for user.

Summary

TypeScript makes JavaScript development very faster with static typing & IntelliSense support. On the other hand, fortjs helps write clean and modular server side code.

Thank you for reading!

#node-js #Rest API #typescript #fortjs

What is GEEK

Buddha Community

How to Create REST API in Node.js with TypeScript and Fortjs
Easter  Deckow

Easter Deckow

1655630160

PyTumblr: A Python Tumblr API v2 Client

PyTumblr

Installation

Install via pip:

$ pip install pytumblr

Install from source:

$ git clone https://github.com/tumblr/pytumblr.git
$ cd pytumblr
$ python setup.py install

Usage

Create a client

A pytumblr.TumblrRestClient is the object you'll make all of your calls to the Tumblr API through. Creating one is this easy:

client = pytumblr.TumblrRestClient(
    '<consumer_key>',
    '<consumer_secret>',
    '<oauth_token>',
    '<oauth_secret>',
)

client.info() # Grabs the current user information

Two easy ways to get your credentials to are:

  1. The built-in interactive_console.py tool (if you already have a consumer key & secret)
  2. The Tumblr API console at https://api.tumblr.com/console
  3. Get sample login code at https://api.tumblr.com/console/calls/user/info

Supported Methods

User Methods

client.info() # get information about the authenticating user
client.dashboard() # get the dashboard for the authenticating user
client.likes() # get the likes for the authenticating user
client.following() # get the blogs followed by the authenticating user

client.follow('codingjester.tumblr.com') # follow a blog
client.unfollow('codingjester.tumblr.com') # unfollow a blog

client.like(id, reblogkey) # like a post
client.unlike(id, reblogkey) # unlike a post

Blog Methods

client.blog_info(blogName) # get information about a blog
client.posts(blogName, **params) # get posts for a blog
client.avatar(blogName) # get the avatar for a blog
client.blog_likes(blogName) # get the likes on a blog
client.followers(blogName) # get the followers of a blog
client.blog_following(blogName) # get the publicly exposed blogs that [blogName] follows
client.queue(blogName) # get the queue for a given blog
client.submission(blogName) # get the submissions for a given blog

Post Methods

Creating posts

PyTumblr lets you create all of the various types that Tumblr supports. When using these types there are a few defaults that are able to be used with any post type.

The default supported types are described below.

  • state - a string, the state of the post. Supported types are published, draft, queue, private
  • tags - a list, a list of strings that you want tagged on the post. eg: ["testing", "magic", "1"]
  • tweet - a string, the string of the customized tweet you want. eg: "Man I love my mega awesome post!"
  • date - a string, the customized GMT that you want
  • format - a string, the format that your post is in. Support types are html or markdown
  • slug - a string, the slug for the url of the post you want

We'll show examples throughout of these default examples while showcasing all the specific post types.

Creating a photo post

Creating a photo post supports a bunch of different options plus the described default options * caption - a string, the user supplied caption * link - a string, the "click-through" url for the photo * source - a string, the url for the photo you want to use (use this or the data parameter) * data - a list or string, a list of filepaths or a single file path for multipart file upload

#Creates a photo post using a source URL
client.create_photo(blogName, state="published", tags=["testing", "ok"],
                    source="https://68.media.tumblr.com/b965fbb2e501610a29d80ffb6fb3e1ad/tumblr_n55vdeTse11rn1906o1_500.jpg")

#Creates a photo post using a local filepath
client.create_photo(blogName, state="queue", tags=["testing", "ok"],
                    tweet="Woah this is an incredible sweet post [URL]",
                    data="/Users/johnb/path/to/my/image.jpg")

#Creates a photoset post using several local filepaths
client.create_photo(blogName, state="draft", tags=["jb is cool"], format="markdown",
                    data=["/Users/johnb/path/to/my/image.jpg", "/Users/johnb/Pictures/kittens.jpg"],
                    caption="## Mega sweet kittens")

Creating a text post

Creating a text post supports the same options as default and just a two other parameters * title - a string, the optional title for the post. Supports markdown or html * body - a string, the body of the of the post. Supports markdown or html

#Creating a text post
client.create_text(blogName, state="published", slug="testing-text-posts", title="Testing", body="testing1 2 3 4")

Creating a quote post

Creating a quote post supports the same options as default and two other parameter * quote - a string, the full text of the qote. Supports markdown or html * source - a string, the cited source. HTML supported

#Creating a quote post
client.create_quote(blogName, state="queue", quote="I am the Walrus", source="Ringo")

Creating a link post

  • title - a string, the title of post that you want. Supports HTML entities.
  • url - a string, the url that you want to create a link post for.
  • description - a string, the desciption of the link that you have
#Create a link post
client.create_link(blogName, title="I like to search things, you should too.", url="https://duckduckgo.com",
                   description="Search is pretty cool when a duck does it.")

Creating a chat post

Creating a chat post supports the same options as default and two other parameters * title - a string, the title of the chat post * conversation - a string, the text of the conversation/chat, with diablog labels (no html)

#Create a chat post
chat = """John: Testing can be fun!
Renee: Testing is tedious and so are you.
John: Aw.
"""
client.create_chat(blogName, title="Renee just doesn't understand.", conversation=chat, tags=["renee", "testing"])

Creating an audio post

Creating an audio post allows for all default options and a has 3 other parameters. The only thing to keep in mind while dealing with audio posts is to make sure that you use the external_url parameter or data. You cannot use both at the same time. * caption - a string, the caption for your post * external_url - a string, the url of the site that hosts the audio file * data - a string, the filepath of the audio file you want to upload to Tumblr

#Creating an audio file
client.create_audio(blogName, caption="Rock out.", data="/Users/johnb/Music/my/new/sweet/album.mp3")

#lets use soundcloud!
client.create_audio(blogName, caption="Mega rock out.", external_url="https://soundcloud.com/skrillex/sets/recess")

Creating a video post

Creating a video post allows for all default options and has three other options. Like the other post types, it has some restrictions. You cannot use the embed and data parameters at the same time. * caption - a string, the caption for your post * embed - a string, the HTML embed code for the video * data - a string, the path of the file you want to upload

#Creating an upload from YouTube
client.create_video(blogName, caption="Jon Snow. Mega ridiculous sword.",
                    embed="http://www.youtube.com/watch?v=40pUYLacrj4")

#Creating a video post from local file
client.create_video(blogName, caption="testing", data="/Users/johnb/testing/ok/blah.mov")

Editing a post

Updating a post requires you knowing what type a post you're updating. You'll be able to supply to the post any of the options given above for updates.

client.edit_post(blogName, id=post_id, type="text", title="Updated")
client.edit_post(blogName, id=post_id, type="photo", data="/Users/johnb/mega/awesome.jpg")

Reblogging a Post

Reblogging a post just requires knowing the post id and the reblog key, which is supplied in the JSON of any post object.

client.reblog(blogName, id=125356, reblog_key="reblog_key")

Deleting a post

Deleting just requires that you own the post and have the post id

client.delete_post(blogName, 123456) # Deletes your post :(

A note on tags: When passing tags, as params, please pass them as a list (not a comma-separated string):

client.create_text(blogName, tags=['hello', 'world'], ...)

Getting notes for a post

In order to get the notes for a post, you need to have the post id and the blog that it is on.

data = client.notes(blogName, id='123456')

The results include a timestamp you can use to make future calls.

data = client.notes(blogName, id='123456', before_timestamp=data["_links"]["next"]["query_params"]["before_timestamp"])

Tagged Methods

# get posts with a given tag
client.tagged(tag, **params)

Using the interactive console

This client comes with a nice interactive console to run you through the OAuth process, grab your tokens (and store them for future use).

You'll need pyyaml installed to run it, but then it's just:

$ python interactive-console.py

and away you go! Tokens are stored in ~/.tumblr and are also shared by other Tumblr API clients like the Ruby client.

Running tests

The tests (and coverage reports) are run with nose, like this:

python setup.py test

Author: tumblr
Source Code: https://github.com/tumblr/pytumblr
License: Apache-2.0 license

#python #api 

NBB: Ad-hoc CLJS Scripting on Node.js

Nbb

Not babashka. Node.js babashka!?

Ad-hoc CLJS scripting on Node.js.

Status

Experimental. Please report issues here.

Goals and features

Nbb's main goal is to make it easy to get started with ad hoc CLJS scripting on Node.js.

Additional goals and features are:

  • Fast startup without relying on a custom version of Node.js.
  • Small artifact (current size is around 1.2MB).
  • First class macros.
  • Support building small TUI apps using Reagent.
  • Complement babashka with libraries from the Node.js ecosystem.

Requirements

Nbb requires Node.js v12 or newer.

How does this tool work?

CLJS code is evaluated through SCI, the same interpreter that powers babashka. Because SCI works with advanced compilation, the bundle size, especially when combined with other dependencies, is smaller than what you get with self-hosted CLJS. That makes startup faster. The trade-off is that execution is less performant and that only a subset of CLJS is available (e.g. no deftype, yet).

Usage

Install nbb from NPM:

$ npm install nbb -g

Omit -g for a local install.

Try out an expression:

$ nbb -e '(+ 1 2 3)'
6

And then install some other NPM libraries to use in the script. E.g.:

$ npm install csv-parse shelljs zx

Create a script which uses the NPM libraries:

(ns script
  (:require ["csv-parse/lib/sync$default" :as csv-parse]
            ["fs" :as fs]
            ["path" :as path]
            ["shelljs$default" :as sh]
            ["term-size$default" :as term-size]
            ["zx$default" :as zx]
            ["zx$fs" :as zxfs]
            [nbb.core :refer [*file*]]))

(prn (path/resolve "."))

(prn (term-size))

(println (count (str (fs/readFileSync *file*))))

(prn (sh/ls "."))

(prn (csv-parse "foo,bar"))

(prn (zxfs/existsSync *file*))

(zx/$ #js ["ls"])

Call the script:

$ nbb script.cljs
"/private/tmp/test-script"
#js {:columns 216, :rows 47}
510
#js ["node_modules" "package-lock.json" "package.json" "script.cljs"]
#js [#js ["foo" "bar"]]
true
$ ls
node_modules
package-lock.json
package.json
script.cljs

Macros

Nbb has first class support for macros: you can define them right inside your .cljs file, like you are used to from JVM Clojure. Consider the plet macro to make working with promises more palatable:

(defmacro plet
  [bindings & body]
  (let [binding-pairs (reverse (partition 2 bindings))
        body (cons 'do body)]
    (reduce (fn [body [sym expr]]
              (let [expr (list '.resolve 'js/Promise expr)]
                (list '.then expr (list 'clojure.core/fn (vector sym)
                                        body))))
            body
            binding-pairs)))

Using this macro we can look async code more like sync code. Consider this puppeteer example:

(-> (.launch puppeteer)
      (.then (fn [browser]
               (-> (.newPage browser)
                   (.then (fn [page]
                            (-> (.goto page "https://clojure.org")
                                (.then #(.screenshot page #js{:path "screenshot.png"}))
                                (.catch #(js/console.log %))
                                (.then #(.close browser)))))))))

Using plet this becomes:

(plet [browser (.launch puppeteer)
       page (.newPage browser)
       _ (.goto page "https://clojure.org")
       _ (-> (.screenshot page #js{:path "screenshot.png"})
             (.catch #(js/console.log %)))]
      (.close browser))

See the puppeteer example for the full code.

Since v0.0.36, nbb includes promesa which is a library to deal with promises. The above plet macro is similar to promesa.core/let.

Startup time

$ time nbb -e '(+ 1 2 3)'
6
nbb -e '(+ 1 2 3)'   0.17s  user 0.02s system 109% cpu 0.168 total

The baseline startup time for a script is about 170ms seconds on my laptop. When invoked via npx this adds another 300ms or so, so for faster startup, either use a globally installed nbb or use $(npm bin)/nbb script.cljs to bypass npx.

Dependencies

NPM dependencies

Nbb does not depend on any NPM dependencies. All NPM libraries loaded by a script are resolved relative to that script. When using the Reagent module, React is resolved in the same way as any other NPM library.

Classpath

To load .cljs files from local paths or dependencies, you can use the --classpath argument. The current dir is added to the classpath automatically. So if there is a file foo/bar.cljs relative to your current dir, then you can load it via (:require [foo.bar :as fb]). Note that nbb uses the same naming conventions for namespaces and directories as other Clojure tools: foo-bar in the namespace name becomes foo_bar in the directory name.

To load dependencies from the Clojure ecosystem, you can use the Clojure CLI or babashka to download them and produce a classpath:

$ classpath="$(clojure -A:nbb -Spath -Sdeps '{:aliases {:nbb {:replace-deps {com.github.seancorfield/honeysql {:git/tag "v2.0.0-rc5" :git/sha "01c3a55"}}}}}')"

and then feed it to the --classpath argument:

$ nbb --classpath "$classpath" -e "(require '[honey.sql :as sql]) (sql/format {:select :foo :from :bar :where [:= :baz 2]})"
["SELECT foo FROM bar WHERE baz = ?" 2]

Currently nbb only reads from directories, not jar files, so you are encouraged to use git libs. Support for .jar files will be added later.

Current file

The name of the file that is currently being executed is available via nbb.core/*file* or on the metadata of vars:

(ns foo
  (:require [nbb.core :refer [*file*]]))

(prn *file*) ;; "/private/tmp/foo.cljs"

(defn f [])
(prn (:file (meta #'f))) ;; "/private/tmp/foo.cljs"

Reagent

Nbb includes reagent.core which will be lazily loaded when required. You can use this together with ink to create a TUI application:

$ npm install ink

ink-demo.cljs:

(ns ink-demo
  (:require ["ink" :refer [render Text]]
            [reagent.core :as r]))

(defonce state (r/atom 0))

(doseq [n (range 1 11)]
  (js/setTimeout #(swap! state inc) (* n 500)))

(defn hello []
  [:> Text {:color "green"} "Hello, world! " @state])

(render (r/as-element [hello]))

Promesa

Working with callbacks and promises can become tedious. Since nbb v0.0.36 the promesa.core namespace is included with the let and do! macros. An example:

(ns prom
  (:require [promesa.core :as p]))

(defn sleep [ms]
  (js/Promise.
   (fn [resolve _]
     (js/setTimeout resolve ms))))

(defn do-stuff
  []
  (p/do!
   (println "Doing stuff which takes a while")
   (sleep 1000)
   1))

(p/let [a (do-stuff)
        b (inc a)
        c (do-stuff)
        d (+ b c)]
  (prn d))
$ nbb prom.cljs
Doing stuff which takes a while
Doing stuff which takes a while
3

Also see API docs.

Js-interop

Since nbb v0.0.75 applied-science/js-interop is available:

(ns example
  (:require [applied-science.js-interop :as j]))

(def o (j/lit {:a 1 :b 2 :c {:d 1}}))

(prn (j/select-keys o [:a :b])) ;; #js {:a 1, :b 2}
(prn (j/get-in o [:c :d])) ;; 1

Most of this library is supported in nbb, except the following:

  • destructuring using :syms
  • property access using .-x notation. In nbb, you must use keywords.

See the example of what is currently supported.

Examples

See the examples directory for small examples.

Also check out these projects built with nbb:

API

See API documentation.

Migrating to shadow-cljs

See this gist on how to convert an nbb script or project to shadow-cljs.

Build

Prequisites:

  • babashka >= 0.4.0
  • Clojure CLI >= 1.10.3.933
  • Node.js 16.5.0 (lower version may work, but this is the one I used to build)

To build:

  • Clone and cd into this repo
  • bb release

Run bb tasks for more project-related tasks.

Download Details:
Author: borkdude
Download Link: Download The Source Code
Official Website: https://github.com/borkdude/nbb 
License: EPL-1.0

#node #javascript

Wilford  Pagac

Wilford Pagac

1594289280

What is REST API? An Overview | Liquid Web

What is REST?

The REST acronym is defined as a “REpresentational State Transfer” and is designed to take advantage of existing HTTP protocols when used for Web APIs. It is very flexible in that it is not tied to resources or methods and has the ability to handle different calls and data formats. Because REST API is not constrained to an XML format like SOAP, it can return multiple other formats depending on what is needed. If a service adheres to this style, it is considered a “RESTful” application. REST allows components to access and manage functions within another application.

REST was initially defined in a dissertation by Roy Fielding’s twenty years ago. He proposed these standards as an alternative to SOAP (The Simple Object Access Protocol is a simple standard for accessing objects and exchanging structured messages within a distributed computing environment). REST (or RESTful) defines the general rules used to regulate the interactions between web apps utilizing the HTTP protocol for CRUD (create, retrieve, update, delete) operations.

What is an API?

An API (or Application Programming Interface) provides a method of interaction between two systems.

What is a RESTful API?

A RESTful API (or application program interface) uses HTTP requests to GET, PUT, POST, and DELETE data following the REST standards. This allows two pieces of software to communicate with each other. In essence, REST API is a set of remote calls using standard methods to return data in a specific format.

The systems that interact in this manner can be very different. Each app may use a unique programming language, operating system, database, etc. So, how do we create a system that can easily communicate and understand other apps?? This is where the Rest API is used as an interaction system.

When using a RESTful API, we should determine in advance what resources we want to expose to the outside world. Typically, the RESTful API service is implemented, keeping the following ideas in mind:

  • Format: There should be no restrictions on the data exchange format
  • Implementation: REST is based entirely on HTTP
  • Service Definition: Because REST is very flexible, API can be modified to ensure the application understands the request/response format.
  • The RESTful API focuses on resources and how efficiently you perform operations with it using HTTP.

The features of the REST API design style state:

  • Each entity must have a unique identifier.
  • Standard methods should be used to read and modify data.
  • It should provide support for different types of resources.
  • The interactions should be stateless.

For REST to fit this model, we must adhere to the following rules:

  • Client-Server Architecture: The interface is separate from the server-side data repository. This affords flexibility and the development of components independently of each other.
  • Detachment: The client connections are not stored on the server between requests.
  • Cacheability: It must be explicitly stated whether the client can store responses.
  • Multi-level: The API should work whether it interacts directly with a server or through an additional layer, like a load balancer.

#tutorials #api #application #application programming interface #crud #http #json #programming #protocols #representational state transfer #rest #rest api #rest api graphql #rest api json #rest api xml #restful #soap #xml #yaml

An API-First Approach For Designing Restful APIs | Hacker Noon

I’ve been working with Restful APIs for some time now and one thing that I love to do is to talk about APIs.

So, today I will show you how to build an API using the API-First approach and Design First with OpenAPI Specification.

First thing first, if you don’t know what’s an API-First approach means, it would be nice you stop reading this and check the blog post that I wrote to the Farfetchs blog where I explain everything that you need to know to start an API using API-First.

Preparing the ground

Before you get your hands dirty, let’s prepare the ground and understand the use case that will be developed.

Tools

If you desire to reproduce the examples that will be shown here, you will need some of those items below.

  • NodeJS
  • OpenAPI Specification
  • Text Editor (I’ll use VSCode)
  • Command Line

Use Case

To keep easy to understand, let’s use the Todo List App, it is a very common concept beyond the software development community.

#api #rest-api #openai #api-first-development #api-design #apis #restful-apis #restful-api

Lets Cms

Lets Cms

1652251629

Unilevel MLM Wordpress Rest API FrontEnd | UMW Rest API Woocommerce

Unilevel MLM Wordpress Rest API FrontEnd | UMW Rest API Woocommerce Price USA, Philippines : Our API’s handle the Unilevel MLM woo-commerce end user all functionalities like customer login/register. You can request any type of information which is listed below, our API will provide you managed results for your all frontend needs, which will be useful for your applications like Mobile App etc.
Business to Customer REST API for Unilevel MLM Woo-Commerce will empower your Woo-commerce site with the most powerful Unilevel MLM Woo-Commerce REST API, you will be able to get and send data to your marketplace from other mobile apps or websites using HTTP Rest API request.
Our plugin is used JWT authentication for the authorization process.

REST API Unilevel MLM Woo-commerce plugin contains following APIs.
User Login Rest API
User Register Rest API
User Join Rest API
Get User info Rest API
Get Affiliate URL Rest API 
Get Downlines list Rest API
Get Bank Details Rest API
Save Bank Details Rest API
Get Genealogy JSON Rest API
Get Total Earning Rest API
Get Current Balance Rest API
Get Payout Details Rest API
Get Payout List Rest API
Get Commissions List Rest API
Withdrawal Request Rest API
Get Withdrawal List Rest API

If you want to know more information and any queries regarding Unilevel MLM Rest API Woocommerce WordPress Plugin, you can contact our experts through 
Skype: jks0586, 
Mail: letscmsdev@gmail.com,
Website: www.letscms.com, www.mlmtrees.com,
Call/WhatsApp/WeChat: +91-9717478599.  

more information : https://www.mlmtrees.com/product/unilevel-mlm-woocommerce-rest-api-addon

Visit Documentation : https://letscms.com/documents/umw_apis/umw-apis-addon-documentation.html

#Unilevel_MLM_WooCommerce_Rest_API's_Addon #umw_mlm_rest_api #rest_api_woocommerce_unilevel #rest_api_in_woocommerce #rest_api_woocommerce #rest_api_woocommerce_documentation #rest_api_woocommerce_php #api_rest_de_woocommerce #woocommerce_rest_api_in_android #woocommerce_rest_api_in_wordpress #Rest_API_Woocommerce_unilevel_mlm #wp_rest_api_woocommerce