No Result
View All Result
CloudReports
  • Home
  • Linux
  • Web development
  • Javascript
  • SQL
  • Ant Design tutorial
  • QR Code Scanner
  • Home
  • Linux
  • Web development
  • Javascript
  • SQL
  • Ant Design tutorial
  • QR Code Scanner
No Result
View All Result
CloudReports
No Result
View All Result
Home Web development

Create custom self-api Next.js api server

npn by npn
July 26, 2019
in Web development
Reading Time: 11 mins read
0
Create custom self-api Next.js api server
0
SHARES
4k
VIEWS
Share on FacebookShare on Twitter

Contents

  • 1 READ ALSO
  • 2 What is the location of the MySQL databases?
  • 3 Top 10 Best WordPress SEO themes of 2022
        • 3.0.0.1 Prepare some resources:
        • 3.0.0.2 Create libs dir:
        • 3.0.0.3 Create file libs/dataProvider.js with this content
        • 3.0.0.4 Modify server.js file:
        • 3.0.0.5 Modify pages/conditionalBuild.jsx and change getInitialProps to
        • 3.0.0.6 Now it is time for our tricky require:
        • 3.0.0.7 Conclusion
Rate this post

Have you ever think about connect to Mysql database or Mongodb database with NextJs?

READ ALSO

What is the location of the MySQL databases?

What is the location of the MySQL databases?

April 24, 2022
597
Top 10 Best WordPress SEO themes of 2022

Top 10 Best WordPress SEO themes of 2022

March 16, 2022
490

Or have you asked some questions as:

  • How to connect to a database with NextJs?
  • How not to create a separate api server for NextJs?
  • How to require server file inside a NextJs page?

Well, you may know that Next.js is a great framework for creating server side rendering application. I just try Next.js for a few months and was very excited about it’s design and easy to use.

Check out these tutorials about Next.js

Next.js + Ant Design with less – Advanced Nextjs and Ant design scaffolding

Convert HTML template into NextJs app

NextJs + KoaJs Create custom NextJs server with KoaJs

[Tutorial] Create react based server side rendering app with NextJS

NextJs Data fetching – Combine Server Side and Client Side fetching

Cloudreports – Next.js tutorials

Next.js was fully supported server side rendering. For now, it may be the best choice for building react based SSR website.

Follow this post NextJs Data fetching, we have got a method for fetching data with Next.js through getInitialProps. But this method is still have disadvantages: You have to build an external api system for NextJs app to work!

Why external api system is a problem here?

Firstly, with external api, you have to build a separate app that work as data provider. Manage two separate Nodejs apps for a simple web is complex.

Secondly, when you have more than one app, you also have to manage more complex deploy, maintain, upgrade process.

And last, when in development, it is not convenience to work on two separated projects while you “should” work on single one.

Why NextJs support SSR, it work as a real SSR system and you still have to build api? Like a CSR SPA???

In this post, we will follow an idea that help answer some questions like these:

  1. Can i merge external api service and NextJs app in to one?
  2. Can i use database or connect to a database in NextJs app?
  3. If i have important information and want to use it in getInitialProps, how can i secure these information?

Because NextJs will expose getInitialProps for both client side and server side, so if you put any code here, you it will be exposed to both side code. It will be bad practice if you put any secure information here. This is also the reason why NextJs official document only saying about fetching data from external api.

Any code inside getInitialProps must be compatible with server side and client side code, any script that only work on server side will cause error during NextJs build process. This is the reason why you cannot do Database connect inside getInitialProps, you shouldn’t put any server side logic here.

You may give up here but slow down, there is something else that help 😀

Before go deep into the solution, i will describe something about NextJs build process.

NextJs won’t build whole server side and client side code at once, because the runtime and environment for these sides are difference. So NextJs will use difference config, difference process for building each side code.

Beside that, NextJs also expose some special variables during the build process. We can use these variables for optimize our source code. Bellow are some use case of exposed NextJs variable:

  • Using as environment variables: these variables will be use while build process (not runtime)
  • Use for conditional building: you may change some setting based on build environment (development, production)
  • Use for minified source code without losing readability

Take a look at Use for conditional building can you guest what is it mean?

One of the build variables you should noted is: process.browser. In client side building, it will be passed as true and in opposite undefined for server side building.

Let me explain through this example:

Create file pages/conditionalBuild.jsx

import React from 'react'

export default class ConditionalBuildingPage extends React.Component {
	static async getInitialProps() {
		let resultText = '';

		if (process.browser) {
			resultText = 'This is text for CLIENT'
		} else {
			resultText = 'This is text for SERVER'
		}

		return {text: resultText}
	}

	render() {
		return <div>{this.props.text}</div>
	}
}

run npm run dev then navigate your browser to http://127.0.0.1:3000/conditionalBuild

When NextJs running build, it will create two directory inside .next

  • server for storage server side code
  • static for storage client side code

Look at these files:

  • .next/static/development/pages/conditionalBuild.js
  • .next/server/static/development/pages/conditionalBuild.js

in both two file, find this text: key: "getInitialProps" and look into followed script

This is the result:

File: .next/static/development/pages/conditionalBuild.js

Built result for client side code

File: .next/server/static/development/pages/conditionalBuild.js

Built result for server side code

Surprised!!! Instead of expose full code in original getInitialProps, NextJs (with help of webpack/babel) was by pass the check condition. While building, NextJs can check the build variables and decided which code to be expose; it will remove unnecessary code on each side and only keep the usable part. So, the point here is that: Client side code won’t consists Server side code. Server side code won’t be mixed with Client side code too. So awesome!!!

Now, do you think about what you can do next? Did you got the answers for three questions at the starting :D? If not, keep calm and i will give you the answers :v

The idea is quite simple! Instead of calling api on both client side and server side, we will ony do it on client side code. The api used for client fetching will be a “local api”. These apis are served through our NextJs Custom Server.
On server side, we will call direct service inside server source code!

Let’s start on doing this awesome thing!

Imagining we have to create a component that display a list of some countries.

First of all, clone this repository and switch to branch custom-server-koajs

https://github.com/cloudreports/my-nextjs/tree/custom-server-koajs
Prepare some resources:
Create libs dir:
mkdir libs
Create file libs/dataProvider.js with this content
exports.countryList = () => {
	return [
        {"name": "Australia", "code": "AU"}, 
        {"name": "Austria", "code": "AT"}, 
        {"name": "Azerbaijan", "code": "AZ"}, 
        {"name": "Bahamas", "code": "BS"}, 
        {"name": "Bahrain", "code": "BH"}, 
        {"name": "Bangladesh", "code": "BD"}, 
        {"name": "Barbados", "code": "BB"}, 
        {"name": "Belarus", "code": "BY"}, 
        {"name": "Belgium", "code": "BE"}, 
        {"name": "Belize", "code": "BZ"}, 
        {"name": "Benin", "code": "BJ"}, 
        {"name": "Bermuda", "code": "BM"}, 
        {"name": "Bhutan", "code": "BT"}, 
        {"name": "Bolivia", "code": "BO"}, 
        {"name": "Bosnia and Herzegovina", "code": "BA"}, 
        {"name": "Botswana", "code": "BW"}, 
        {"name": "Bouvet Island", "code": "BV"}, 
        {"name": "Brazil", "code": "BR"}, 
        {"name": "British Indian Ocean Territory", "code": "IO"}, 
        {"name": "Brunei Darussalam", "code": "BN"}, 
        {"name": "Bulgaria", "code": "BG"}, 
        {"name": "Burkina Faso", "code": "BF"}, 
        {"name": "Burundi", "code": "BI"}, 
        {"name": "Cambodia", "code": "KH"}, 
        {"name": "Cameroon", "code": "CM"}, 
        {"name": "Canada", "code": "CA"}, 
        {"name": "Cape Verde", "code": "CV"}
    ];
}
Modify server.js file:
  • Add this line after const handler = nextApp.getRequestHandler();
  • Add these lines before router.get('*', async ctx => { (this is important)
global.SERVER_APP_ROOT = __dirname;
const dataProvider = require(SERVER_APP_ROOT + '/libs/dataProvider');
router.get('/api/country', async ctx => {
	ctx.body = dataProvider.countryList();
});

Start NextJs server and check if api http://127.0.0.1:3000/api/country worked.

We will continue by working with ConditionalBuildingPage component inside pages/conditionalBuild.jsx

Look at this script (we will call this: S1), it will describe the idea of self-api-server

let conditionalDataProvider = null;

if (process.browser) {
	conditionalDataProvider = async () => {	
		let res = await fetch('http://127.0.0.1:3000/api/country');
		let countries = await res.json();
		
		return countries;
	}
} else {
	conditionalDataProvider = async () => {	
		const dataProvider = require(SERVER_APP_ROOT + '/libs/dataProvider.js');
		let countries = dataProvider.countryList();
		
		return countries;
	}
}

As you can see, in above script we check if the current built is for client or server. If this built is for client, we will call api that we defined before. If it is for server, we will directly get data from dataProvider

ADVERTISEMENT
Modify pages/conditionalBuild.jsx and change getInitialProps to
static async getInitialProps() {
    let countries = await conditionalDataProvider();

    return {countries}
}

Add function S1 after line import React from 'react'

Change function render to

render() {
    return (
        <div>
            <h1>Country list</h1>
            <ul>
                {this.props.countries.map((country, i) => {
                    return (
                        <li key={'country-' + i}>{country.name}</li>
                    )
                })}
            </ul>
        </div>
    )
}

Restart NextJs server and check http://127.0.0.1:3000/conditionalBuild

wow, we got an error: Unhandled Rejection (Error): Cannot find module

The reason is that, when webpack compile source, it will convert require to __webpack_require__ and __webpack_require__ does not understand dataProvider.js file path. We can config web pack to include libs/* into it built. But there are some reasons prevent us do this:

Our idea is that we will put some logic code that work only on server side inside libsdirectory. These code may be do database connecting, hash or any thing else that should be secure. We don’t need to build these code by webpack, it should be run as a normal javascript file.
There are many library that writen in es5, they just use require and exports. When mixing with component file (jsx files), we have to config so many complicated thing. If not, webpack will throw error on build process, or if it success on build process, then the built file should not work as expected
Re-building all the files that does not required will only cause the build process take more time, and it is not a good practice too.

Now it is time for our tricky require:

Modify pages/conditionalBuild.jsx and  change

const dataProvider = require(SERVER_APP_ROOT + '/libs/dataProvider.js');

to

const dataProvider = eval("require('" + SERVER_APP_ROOT + "/libs/dataProvider')");

Restart your NextJs server and reload 127.0.0.1:3000/conditionalBuild

now it work as expected!

Let me explain about the reason for using eval in this case

When using eval, require command is passed as string. Webpack will not analyze any thing inside this string, this require part is only existed in webpack build as a normal parameter!

Conclusion

This tutorial present a simple idea for design a better NextJs app (IMO), follow this tutorial, you may have a generality look about this idea.
Look at file libs/dataProvider.js, this file is just a normal js file. But the way it was called inside server.js and conditionalBuild.jsx is the key here
Inside libs/dataProvider.js you can do almost thing as a normal NodeJs file, these can be:

  • Connect to database (it is what called “Connect database inside NextJs app`)
  • Hashing/Encrypting/Decrypting…
  • Storage server side secure logic

Well, i hope you understand my idea and can apply this on your project! If i have any mistakes or if you have any problem while following this tutorial, please let me know.

Thank you!

Git repo for this turotial:
https://github.com/cloudreports/my-nextjs/tree/custom-self-api-server

Tags: Next.js
ShareTweetShare
Previous Post

How to solve Github import error: “We found an error during import”

Next Post

NextJs Data fetching – Combine Server Side and Client Side fetching

npn

npn

Related Posts

What is the location of the MySQL databases?
Linux

What is the location of the MySQL databases?

April 24, 2022
597
Top 10 Best WordPress SEO themes of 2022
Web development

Top 10 Best WordPress SEO themes of 2022

March 16, 2022
490
Gmail – Gmail Sign Up – Gmail Login
Web development

Gmail – Gmail Sign Up – Gmail Login

August 30, 2021
7.1k
Configuring VS Code for Node/JavaScript Development
Javascript

Configuring VS Code for Node/JavaScript Development

August 2, 2021
1.3k
How does Nodejs solve the problem of high concurrency?
Javascript

How does Nodejs solve the problem of high concurrency?

July 18, 2021
1.3k
How to create a self-signed SSL certificate for Apache on Ubuntu 16.04
Linux

How to create a self-signed SSL certificate for Apache on Ubuntu 16.04

July 18, 2021
1k
Next Post
fetching data in nextjs

NextJs Data fetching - Combine Server Side and Client Side fetching

Discussion about this post

No Result
View All Result

Categories

  • Android (1)
  • Ant Design tutorial (7)
  • App/Game (2)
  • Javascript (16)
  • Layout and Routing (2)
  • Linux (9)
  • PC & LAPTOP (6)
  • PERSONAL FINANCES (1)
  • React (13)
  • SQL (2)
  • TECHNOLOGY & DIGITAL (7)
  • The Basics (5)
  • Web development (37)

Search

No Result
View All Result

Categories

  • Android (1)
  • Ant Design tutorial (7)
  • App/Game (2)
  • Javascript (16)
  • Layout and Routing (2)
  • Linux (9)
  • PC & LAPTOP (6)
  • PERSONAL FINANCES (1)
  • React (13)
  • SQL (2)
  • TECHNOLOGY & DIGITAL (7)
  • The Basics (5)
  • Web development (37)
No Result
View All Result
  • Home
  • Linux
  • Web development
  • Javascript
  • SQL
  • Ant Design tutorial
  • QR Code Scanner